From 0aba96f66f451d5f1ffe521a57369e21688387ee Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Mon, 25 Apr 2011 22:27:32 +0200 Subject: [PATCH] euscanwww: charts, about, etc... Signed-off-by: Corentin Chary --- euscanwww/euscan/charts.py | 115 ++++++++++++++++++ .../management/commands/scan-metadata.py | 2 +- .../management/commands/scan-portage.py | 16 ++- .../management/commands/update-counters.py | 18 +-- ...verlay__add_field_package_n_overlay__ad.py | 115 ++++++++++++++++++ euscanwww/euscan/models.py | 6 +- euscanwww/euscan/templatetags/div.py | 8 ++ euscanwww/euscan/templatetags/packages.py | 8 ++ euscanwww/euscan/urls.py | 7 +- euscanwww/euscan/views.py | 67 ++++++++-- euscanwww/media/charts/.keep_git | 0 euscanwww/media/css/style.css | 27 +++- euscanwww/media/css/table.css | 32 +---- euscanwww/media/img/django.png | Bin 0 -> 1473 bytes euscanwww/media/img/python.png | Bin 0 -> 3140 bytes euscanwww/settings.py | 1 + euscanwww/templates/_base.html | 17 ++- euscanwww/templates/euscan/_package_bar.html | 9 ++ euscanwww/templates/euscan/_package_cols.html | 24 ++++ euscanwww/templates/euscan/_packages.html | 18 +-- euscanwww/templates/euscan/about.html | 37 ++++++ euscanwww/templates/euscan/categories.html | 23 ++-- euscanwww/templates/euscan/category.html | 5 + euscanwww/templates/euscan/herd.html | 5 + euscanwww/templates/euscan/herds.html | 18 +-- euscanwww/templates/euscan/index.html | 8 +- euscanwww/templates/euscan/maintainer.html | 6 + euscanwww/templates/euscan/maintainers.html | 18 +-- euscanwww/templates/euscan/package.html | 2 +- euscanwww/templates/euscan/statistics.html | 13 ++ 30 files changed, 504 insertions(+), 121 deletions(-) create mode 100644 euscanwww/euscan/charts.py create mode 100644 euscanwww/euscan/migrations/0003_auto__add_field_categorylog_n_overlay__add_field_package_n_overlay__ad.py create mode 100644 euscanwww/euscan/templatetags/div.py create mode 100644 euscanwww/media/charts/.keep_git create mode 100644 euscanwww/media/img/django.png create mode 100644 euscanwww/media/img/python.png create mode 100644 euscanwww/templates/euscan/_package_bar.html create mode 100644 euscanwww/templates/euscan/_package_cols.html create mode 100644 euscanwww/templates/euscan/about.html create mode 100644 euscanwww/templates/euscan/statistics.html diff --git a/euscanwww/euscan/charts.py b/euscanwww/euscan/charts.py new file mode 100644 index 0000000..3d188b7 --- /dev/null +++ b/euscanwww/euscan/charts.py @@ -0,0 +1,115 @@ +import os.path +import time + +from euscanwww import settings + +from django.db.models import F, Sum, Max +from euscan.models import Version, Package, Herd, Maintainer +from euscan.models import CategoryLog + +import pylab +import matplotlib + +CHARTS_ROOT = os.path.join(settings.MEDIA_ROOT, "charts") +CHARTS_URL = os.path.join(settings.MEDIA_URL, "charts") +CHARTS_TTL = (24 * 60 * 60) + +pylab.rcParams['font.size'] = 10.0 +pylab.rcParams['axes.titlesize'] = 10.0 +pylab.rcParams['xtick.labelsize'] = 8.0 +pylab.rcParams['legend.fontsize'] = 8.0 + +def xint(i): + try: + return int(i) + except: + return 0 + +def chart_alive(name): + path = os.path.join(CHARTS_ROOT, name) + if not os.path.exists(path): + return False + if os.path.getmtime(__file__) > os.path.getmtime(path): + return False + if os.path.getmtime(path) + CHARTS_TTL < time.time(): + return False + return True + +def chart_name(name, **kwargs): + if 'category' in kwargs and kwargs['category']: + name += '-%s' % kwargs['category'] + if 'herd' in kwargs and kwargs['herd']: + name += '-h-%d' % kwargs['herd'].id + if 'maintainer' in kwargs and kwargs['maintainer']: + name += '-m-%d' % kwargs['maintainer'].id + return name + ".png" + +def packages(**kwargs): + packages = Package.objects + + if 'category' in kwargs and kwargs['category']: + packages = packages.filter(category=kwargs['category']) + if 'herd' in kwargs and kwargs['herd']: + packages = packages.filter(herds__id=kwargs['herd'].id) + if 'maintainer' in kwargs and kwargs['maintainer']: + packages = packages.filter(maintainers__id=kwargs['maintainer'].id) + + return packages + +def cached_pylab_chart(f): + def new_f(*args, **kwds): + name = chart_name(f.func_name, **kwds) + + if not chart_alive(name): + f(*args, **kwds) + pylab.savefig(os.path.join(CHARTS_ROOT, name)) + pylab.close() + + return name + + new_f.func_name = f.func_name + return new_f + +@cached_pylab_chart +def pie_versions(**kwargs): + n_packaged = xint(packages(**kwargs).aggregate(Sum('n_packaged'))['n_packaged__sum']) + n_overlay = xint(packages(**kwargs).aggregate(Sum('n_overlay'))['n_overlay__sum']) + n_versions = xint(packages(**kwargs).aggregate(Sum('n_versions'))['n_versions__sum']) + n_upstream = n_versions - n_packaged - n_overlay + + pylab.figure(1, figsize=(3.5,3.5)) + + if n_overlay: + labels = 'Gentoo', 'Overlays', 'Upstream' + fracs = [n_packaged, n_overlay, n_upstream] + colors = '#008000', '#0B17FD', '#FF0000' + else: + labels = 'Gentoo', 'Upstream' + fracs = [n_packaged, n_upstream] + colors = '#008000', '#FF0000' + + pylab.pie(fracs, labels=labels, colors=colors, autopct='%1.1f%%', shadow=True) + pylab.title('Versions', bbox={'facecolor':'0.8', 'pad':5}) + +@cached_pylab_chart +def pie_packages(**kwargs): + n_packages = packages(**kwargs).count() + n_packages_uptodate_main = packages(**kwargs).filter(n_versions=F('n_packaged')).count() + n_packages_uptodate_all = packages(**kwargs).filter(n_versions=F('n_packaged') + F('n_overlay')).count() + n_packages_outdated = n_packages - n_packages_uptodate_all + n_packages_uptodate_ovl = n_packages_uptodate_all - n_packages_uptodate_main + + pylab.figure(1, figsize=(3.5,3.5)) + + if n_packages_uptodate_ovl: + labels = 'Ok (gentoo)', 'Ok (overlays)', 'Outdated' + fracs = [n_packages_uptodate_main, n_packages_uptodate_ovl, n_packages_outdated] + colors = '#008000', '#0B17FD', '#FF0000' + else: + labels = 'Ok (gentoo)', 'Outdated' + fracs = [n_packages_uptodate_main, n_packages_outdated] + colors = '#008000', '#FF0000' + + pylab.pie(fracs, labels=labels, colors=colors, autopct='%1.1f%%', shadow=True) + pylab.title('Packages', bbox={'facecolor':'0.8', 'pad':5}) + diff --git a/euscanwww/euscan/management/commands/scan-metadata.py b/euscanwww/euscan/management/commands/scan-metadata.py index f6d0bd0..376ab49 100644 --- a/euscanwww/euscan/management/commands/scan-metadata.py +++ b/euscanwww/euscan/management/commands/scan-metadata.py @@ -62,7 +62,7 @@ class Command(BaseCommand): matches = sorted(matches) pkg = matches.pop() - if pkg.version == '9999' and len(matches): + if '9999' in pkg.version and len(matches): pkg = matches.pop() obj, created = Package.objects.get_or_create(category=pkg.category, name=pkg.name) diff --git a/euscanwww/euscan/management/commands/scan-portage.py b/euscanwww/euscan/management/commands/scan-portage.py index d276742..78b53fe 100644 --- a/euscanwww/euscan/management/commands/scan-portage.py +++ b/euscanwww/euscan/management/commands/scan-portage.py @@ -103,14 +103,14 @@ class Command(BaseCommand): slot = match.group('slot') overlay = match.group('overlay') - if not package or not cpv.startswith(str(package)): - package = self.store_package(options, cpv) + cat, pkg, ver, rev = portage.catpkgsplit(cpv) + + if not package or not (cat == package.category and pkg == package.name): + package = self.store_package(options, cat, pkg) self.store_version(options, package, cpv, slot, overlay) - def store_package(self, options, cpv): - cat, pkg, ver, rev = portage.catpkgsplit(cpv) - + def store_package(self, options, cat, pkg): obj, created = Package.objects.get_or_create(category=cat, name=pkg) if created: @@ -121,6 +121,7 @@ class Command(BaseCommand): Version.objects.filter(package=obj, packaged=True).delete() obj.n_packaged = 0 + obj.n_overlay = 0 obj.n_versions = Version.objects.filter(package=obj).count() obj.save() @@ -144,7 +145,10 @@ class Command(BaseCommand): overlay=overlay) if created or not package.n_packaged: - package.n_packaged += 1 + if overlay == 'gentoo': + package.n_packaged += 1 + else: + package.n_overlay += 1 if created: package.n_versions += 1 diff --git a/euscanwww/euscan/management/commands/update-counters.py b/euscanwww/euscan/management/commands/update-counters.py index 4625f01..1746641 100644 --- a/euscanwww/euscan/management/commands/update-counters.py +++ b/euscanwww/euscan/management/commands/update-counters.py @@ -51,40 +51,44 @@ class Command(BaseCommand): for package in Package.objects.all(): # Should not be needed, but can't hurt package.n_versions = Version.objects.filter(package=package).count() - package.n_packaged != Version.objects.filter(package=package,packaged=True).count() + package.n_packaged = Version.objects.filter(package=package, packaged=True, overlay='gentoo').count() + package.n_overlay = Version.objects.filter(package=package, packaged=True).exclude(overlay='gentoo').count() package.save() for herd in package.herds.all(): herds[herd].n_packages += 1 herds[herd].n_versions += package.n_versions herds[herd].n_packaged += package.n_packaged + herds[herd].n_overlay += package.n_overlay for maintainer in package.maintainers.all(): maintainers[maintainer].n_packages += 1 maintainers[maintainer].n_versions += package.n_versions maintainers[maintainer].n_packaged += package.n_packaged + maintainers[maintainer].n_overlay += package.n_overlay categories[package.category].n_packages += 1 categories[package.category].n_versions += package.n_versions categories[package.category].n_packaged += package.n_packaged + categories[package.category].n_overlay += package.n_overlay for clog in categories.values(): if not options['quiet']: - self.stdout.write('[c] %s - [%d, %d/%d]\n' % + self.stdout.write('[c] %s - [%d, %d/%d/%d]\n' % (clog.category, clog.n_packages, - clog.n_packaged, clog.n_versions)) + clog.n_packaged, clog.n_overlay, clog.n_versions)) clog.save() for hlog in herds.values(): if not options['quiet']: - self.stdout.write('[h] %s - [%d, %d/%d]\n' % + self.stdout.write('[h] %s - [%d, %d/%d/%d]\n' % (hlog.herd, hlog.n_packages, - hlog.n_packaged, hlog.n_versions)) + hlog.n_packaged, hlog.n_overlay, hlog.n_versions)) hlog.save() for mlog in maintainers.values(): if not options['quiet']: - self.stdout.write('[m] %s - [%d, %d/%d]\n' % + self.stdout.write('[m] %s - [%d, %d/%d/%d]\n' % (mlog.maintainer, mlog.n_packages, - mlog.n_packaged, mlog.n_versions)) + mlog.n_packaged, mlog.n_overlay, mlog.n_versions)) mlog.save() diff --git a/euscanwww/euscan/migrations/0003_auto__add_field_categorylog_n_overlay__add_field_package_n_overlay__ad.py b/euscanwww/euscan/migrations/0003_auto__add_field_categorylog_n_overlay__add_field_package_n_overlay__ad.py new file mode 100644 index 0000000..fcef666 --- /dev/null +++ b/euscanwww/euscan/migrations/0003_auto__add_field_categorylog_n_overlay__add_field_package_n_overlay__ad.py @@ -0,0 +1,115 @@ +# encoding: 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 field 'CategoryLog.n_overlay' + db.add_column('euscan_categorylog', 'n_overlay', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False) + + # Adding field 'Package.n_overlay' + db.add_column('euscan_package', 'n_overlay', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False) + + # Adding field 'HerdLog.n_overlay' + db.add_column('euscan_herdlog', 'n_overlay', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False) + + # Adding field 'MaintainerLog.n_overlay' + db.add_column('euscan_maintainerlog', 'n_overlay', self.gf('django.db.models.fields.IntegerField')(default=0), keep_default=False) + + + def backwards(self, orm): + + # Deleting field 'CategoryLog.n_overlay' + db.delete_column('euscan_categorylog', 'n_overlay') + + # Deleting field 'Package.n_overlay' + db.delete_column('euscan_package', 'n_overlay') + + # Deleting field 'HerdLog.n_overlay' + db.delete_column('euscan_herdlog', 'n_overlay') + + # Deleting field 'MaintainerLog.n_overlay' + db.delete_column('euscan_maintainerlog', 'n_overlay') + + + models = { + 'euscan.categorylog': { + 'Meta': {'object_name': 'CategoryLog'}, + 'category': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'datetime': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'n_overlay': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_packaged': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_packages': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_versions': ('django.db.models.fields.IntegerField', [], {'default': '0'}) + }, + 'euscan.euscanresult': { + 'Meta': {'object_name': 'EuscanResult'}, + 'datetime': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'package': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['euscan.Package']"}), + 'result': ('django.db.models.fields.TextField', [], {'blank': 'True'}) + }, + 'euscan.herd': { + 'Meta': {'object_name': 'Herd'}, + 'email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'herd': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'euscan.herdlog': { + 'Meta': {'object_name': 'HerdLog'}, + 'datetime': ('django.db.models.fields.DateTimeField', [], {}), + 'herd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['euscan.Herd']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'n_overlay': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_packaged': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_packages': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_versions': ('django.db.models.fields.IntegerField', [], {'default': '0'}) + }, + 'euscan.maintainer': { + 'Meta': {'object_name': 'Maintainer'}, + 'email': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'euscan.maintainerlog': { + 'Meta': {'object_name': 'MaintainerLog'}, + 'datetime': ('django.db.models.fields.DateTimeField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['euscan.Maintainer']"}), + 'n_overlay': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_packaged': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_packages': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_versions': ('django.db.models.fields.IntegerField', [], {'default': '0'}) + }, + 'euscan.package': { + 'Meta': {'unique_together': "(['category', 'name'],)", 'object_name': 'Package'}, + 'category': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'herds': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['euscan.Herd']", 'symmetrical': 'False', 'blank': 'True'}), + 'homepage': ('django.db.models.fields.CharField', [], {'max_length': '256', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'maintainers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['euscan.Maintainer']", 'symmetrical': 'False', 'blank': 'True'}), + 'n_overlay': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_packaged': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'n_versions': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + }, + 'euscan.version': { + 'Meta': {'unique_together': "(['package', 'slot', 'revision', 'version', 'overlay'],)", 'object_name': 'Version'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'overlay': ('django.db.models.fields.CharField', [], {'default': "'gentoo'", 'max_length': '128'}), + 'package': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['euscan.Package']"}), + 'packaged': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'revision': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'slot': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'urls': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'version': ('django.db.models.fields.CharField', [], {'max_length': '128'}) + } + } + + complete_apps = ['euscan'] diff --git a/euscanwww/euscan/models.py b/euscanwww/euscan/models.py index 7d34b63..3752ffb 100644 --- a/euscanwww/euscan/models.py +++ b/euscanwww/euscan/models.py @@ -27,6 +27,7 @@ class Package(models.Model): # For performance, we keep pre-computed counters n_versions = models.IntegerField(default=0) n_packaged = models.IntegerField(default=0) + n_overlay = models.IntegerField(default=0) def __unicode__(self): return '%s/%s' % (self.category, self.name) @@ -40,7 +41,7 @@ class Version(models.Model): revision = models.CharField(max_length=128) version = models.CharField(max_length=128) packaged = models.BooleanField() - overlay = models.CharField(max_length=128) + overlay = models.CharField(max_length=128, default='gentoo') urls = models.TextField(blank=True) def __unicode__(self): @@ -64,6 +65,7 @@ class CategoryLog(models.Model): n_packages = models.IntegerField(default=0) n_versions = models.IntegerField(default=0) n_packaged = models.IntegerField(default=0) + n_overlay = models.IntegerField(default=0) class HerdLog(models.Model): herd = models.ForeignKey(Herd) @@ -72,6 +74,7 @@ class HerdLog(models.Model): n_packages = models.IntegerField(default=0) n_versions = models.IntegerField(default=0) n_packaged = models.IntegerField(default=0) + n_overlay = models.IntegerField(default=0) class MaintainerLog(models.Model): maintainer = models.ForeignKey(Maintainer) @@ -80,3 +83,4 @@ class MaintainerLog(models.Model): n_packages = models.IntegerField(default=0) n_versions = models.IntegerField(default=0) n_packaged = models.IntegerField(default=0) + n_overlay = models.IntegerField(default=0) diff --git a/euscanwww/euscan/templatetags/div.py b/euscanwww/euscan/templatetags/div.py new file mode 100644 index 0000000..bfa4b20 --- /dev/null +++ b/euscanwww/euscan/templatetags/div.py @@ -0,0 +1,8 @@ +from django import template + +register = template.Library() + +def div(value, arg=None): + return value/arg + +register.filter('div', div) diff --git a/euscanwww/euscan/templatetags/packages.py b/euscanwww/euscan/templatetags/packages.py index 81fb2a3..f953293 100644 --- a/euscanwww/euscan/templatetags/packages.py +++ b/euscanwww/euscan/templatetags/packages.py @@ -5,3 +5,11 @@ register = template.Library() @register.inclusion_tag('euscan/_packages.html') def packages(packages): return { 'packages' : packages } + +@register.inclusion_tag('euscan/_package_cols.html') +def package_cols(infos): + return { 'infos' : infos } + +@register.inclusion_tag('euscan/_package_bar.html') +def package_bar(infos): + return { 'infos' : infos } diff --git a/euscanwww/euscan/urls.py b/euscanwww/euscan/urls.py index 3b026c4..a130cab 100644 --- a/euscanwww/euscan/urls.py +++ b/euscanwww/euscan/urls.py @@ -2,14 +2,19 @@ from django.conf.urls.defaults import * urlpatterns = patterns('euscan.views', (r'^$', 'index'), - (r'^logs/$', 'logs'), + (r'^about/$', 'about'), + (r'^statistics/$', 'statistics'), + (r'^statistics/charts/(?P[\w\-]+).png$', 'chart'), (r'^world/$', 'world'), (r'^world/scan/$', 'world_scan'), (r'^categories/$', 'categories'), (r'^categories/(?P[\w+][\w+.-]*)/view/$', 'category'), + (r'^categories/(?P[\w+][\w+.-]*)/charts/(?P[\w\-]+).png$', 'chart_category'), (r'^herds/$', 'herds'), (r'^herds/(?P[\{\}\w+.-]*)/view/$', 'herd'), + (r'^herds/(?P[\{\}\w+.-]*)/charts/(?P[\w\-]+).png$', 'chart_herd'), (r'^maintainers/$', 'maintainers'), (r'^maintainers/(?P\d+)/view/$', 'maintainer'), + (r'^maintainers/(?P\d+)/charts/(?P[\w\-]+).png$', 'chart_maintainer'), (r'^package/(?P[\w+][\w+.-]*)/(?P[\w+][\w+.-]*)/$', 'package'), ) diff --git a/euscanwww/euscan/views.py b/euscanwww/euscan/views.py index fcd12ca..4a8714f 100644 --- a/euscanwww/euscan/views.py +++ b/euscanwww/euscan/views.py @@ -1,4 +1,5 @@ from annoying.decorators import render_to +from django.http import HttpResponse from django.http import Http404 from django.shortcuts import get_object_or_404 from django.db.models import Sum, Max @@ -6,13 +7,17 @@ from django.db.models import Sum, Max from euscan.models import Version, Package, Herd, Maintainer, EuscanResult from euscan.forms import WorldForm, PackagesForm +import charts + +""" Views """ + @render_to('euscan/index.html') def index(request): ctx = {} - ctx['n_packaged'] = Package.objects.aggregate(Sum('n_packaged'))['n_packaged__sum'] - ctx['n_versions'] = Package.objects.aggregate(Sum('n_versions'))['n_versions__sum'] - if ctx['n_versions'] is not None and ctx['n_packaged'] is not None: - ctx['n_upstream'] = ctx['n_versions'] - ctx['n_packaged'] + ctx['n_packaged'] = charts.xint(Package.objects.aggregate(Sum('n_packaged'))['n_packaged__sum']) + ctx['n_overlay'] = charts.xint(Package.objects.aggregate(Sum('n_overlay'))['n_overlay__sum']) + ctx['n_versions'] = charts.xint(Package.objects.aggregate(Sum('n_versions'))['n_versions__sum']) + ctx['n_upstream'] = ctx['n_versions'] - ctx['n_packaged'] - ctx['n_overlay'] ctx['n_packages'] = Package.objects.count() ctx['n_herds'] = Herd.objects.count() ctx['n_maintainers'] = Maintainer.objects.count() @@ -25,7 +30,10 @@ def logs(request): @render_to('euscan/categories.html') def categories(request): - categories = Package.objects.values('category').annotate(n_packaged=Sum('n_packaged'), n_versions=Sum('n_versions')) + categories = Package.objects.values('category').annotate(n_packaged=Sum('n_packaged'), + n_overlay=Sum('n_overlay'), + n_versions=Sum('n_versions')) + return { 'categories' : categories } @render_to('euscan/category.html') @@ -38,7 +46,10 @@ def category(request, category): @render_to('euscan/herds.html') def herds(request): # FIXME: optimize the query, it uses 'LEFT OUTER JOIN' instead of 'INNER JOIN' - herds = Package.objects.filter(herds__isnull=False).values('herds__herd').annotate(n_packaged=Sum('n_packaged'), n_versions=Sum('n_versions')) + herds = Package.objects.filter(herds__isnull=False) + herds = herds.values('herds__herd').annotate(n_packaged=Sum('n_packaged'), + n_overlay=Sum('n_overlay'), + n_versions=Sum('n_versions')) return { 'herds' : herds } @render_to('euscan/herd.html') @@ -49,7 +60,12 @@ def herd(request, herd): @render_to('euscan/maintainers.html') def maintainers(request): - maintainers = Package.objects.filter(maintainers__isnull=False).values('maintainers__id', 'maintainers__name').annotate(n_packaged=Sum('n_packaged'), n_versions=Sum('n_versions')) + maintainers = Package.objects.filter(maintainers__isnull=False) + maintainers = maintainers.values('maintainers__id', 'maintainers__name') + maintainers = maintainers.annotate(n_packaged=Sum('n_packaged'), + n_overlay=Sum('n_overlay'), + n_versions=Sum('n_versions')) + return { 'maintainers' : maintainers } @render_to('euscan/maintainer.html') @@ -61,6 +77,7 @@ def maintainer(request, maintainer_id): @render_to('euscan/package.html') def package(request, category, package): package = get_object_or_404(Package, category=category, name=package) + package.homepages = package.homepage.split(' ') packaged = Version.objects.filter(package=package, packaged=True) upstream = Version.objects.filter(package=package, packaged=False) log = EuscanResult.objects.filter(package=package).order_by('-datetime')[:1] @@ -99,8 +116,42 @@ def world_scan(request): packages.extend(Package.objects.filter(name=pkg)) except: pass - print packages return { 'packages' : packages } +@render_to("euscan/about.html") +def about(request): + return {} + +@render_to("euscan/statistics.html") +def statistics(request): + return {} + +def chart(request, **kwargs): + from django.views.static import serve + + chart = kwargs['chart'] if 'chart' in kwargs else None + + if 'maintainer_id' in kwargs: + kwargs['maintainer'] = get_object_or_404(Maintainer, id=kwargs['maintainer_id']) + if 'herd' in kwargs: + kwargs['herd'] = get_object_or_404(Herd, herd=kwargs['herd']) + + if chart == 'pie-packages': + path = charts.pie_packages(**kwargs) + elif chart == 'pie-versions': + path = charts.pie_versions(**kwargs) + else: + raise Http404() + + return serve(request, path, document_root=charts.CHARTS_ROOT) + +def chart_maintainer(request, **kwargs): + return chart(request, **kwargs) + +def chart_herd(request, **kwargs): + return chart(request, **kwargs) + +def chart_category(request, **kwargs): + return chart(request, **kwargs) diff --git a/euscanwww/media/charts/.keep_git b/euscanwww/media/charts/.keep_git new file mode 100644 index 0000000..e69de29 diff --git a/euscanwww/media/css/style.css b/euscanwww/media/css/style.css index c42ab14..5ef0f8a 100644 --- a/euscanwww/media/css/style.css +++ b/euscanwww/media/css/style.css @@ -148,10 +148,6 @@ h1 { color:#15B100; } -.bad { - color:#FFFFFF; -} - hr { margin: 0.3em 1em 0.3em 1em; @@ -230,3 +226,26 @@ th clear: both; } +.package_stat { + width: 40px; + float: right; + height: 5px; + border: 1px solid #ccc; +} + +.package_stat div { + float: left; + height: 5px; +} + +.package_stat .packaged { + background: #85ACFF; +} + +.package_stat .overlay { + background: #C6D9FD; +} + +.package_stat .upstream { + background: #FDEADD; +} \ No newline at end of file diff --git a/euscanwww/media/css/table.css b/euscanwww/media/css/table.css index eb159d1..d59a217 100644 --- a/euscanwww/media/css/table.css +++ b/euscanwww/media/css/table.css @@ -184,20 +184,12 @@ table.display td.center { /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DataTables row classes */ -table.display tr.gradeA { - background-color: #ddffdd; +table.display td.bad { + background-color: #FFDFDF; } -table.display tr.gradeC { - background-color: #ddddff; -} - -table.display tr.gradeX { - background-color: #ffdddd; -} - -table.display tr.gradeU { - background-color: #ddd; +table.display td.ugly { + background-color: #EDB9B9; } tr { @@ -335,22 +327,6 @@ table.KeyTable td.focus { border: 3px solid #3366FF; } -table.display tr.gradeA { - background-color: #eeffee; -} - -table.display tr.gradeC { - background-color: #ddddff; -} - -table.display tr.gradeX { - background-color: #ffdddd; -} - -table.display tr.gradeU { - background-color: #ddd; -} - div.box { height: 100px; padding: 10px; diff --git a/euscanwww/media/img/django.png b/euscanwww/media/img/django.png new file mode 100644 index 0000000000000000000000000000000000000000..e1bd21669ff073c86a9df73ddca90661dbba2fbf GIT binary patch literal 1473 zcmV;y1wQ(TP)*nX@<>%(Evasak<=^4p-QV7&s;ArC+}YdOEJHfi+1SN>FVj_=H)O(JuXB$6*Vby ze0WP+RC0WGNm)`yS5R(vb3|254KXAnJ~Rt2A_^}dB0Mr7JTV?RE{>IwjFXUylaDk> zKr=@_xV*bEM?P6*VHY+kR%Bj#gMYEMv{7JLrmU%@s;Hr+q@bpwpQNHGK{zNuHx4o+ z($&-@KQs(5BATF`BRw*ho|~4Onat15l9-jq%gV;d$ou^K#K*?@`uf7f#A9!2_4f9@ z!N9%2zw`9;H%dZYYh}B?y2Ut)YEW!cFoYv z%+Afr&dkcp%S2U9|Ns9&Q%wE+{rmg-KT%2g`})Ji#QFL8`1$x_ZfW)P_4D)d9y%}X z@9ymF>@-P1fQf}KMLZTZDtv{3EJHaIG$<1^CwPH>cMLEi3os&>o}39T zARs$1mYkZCnwO1~k&BX#JYlta00009a7bBm0000;0000;07l7cJ^%m$uSrBfR9M69 zmFZuMQ544?yGUf;C2dF{QA9!tPa5k`qGZXw%aSEzCtH@Nh>$JO*pl@aO9^8a;+N&$ zaGu#rqo)^nVfj4g#l7d;Ilu4Rd+xb20{x~53P1rU00r>>0m5`Tok*R%ywWNNhy$Re z=|Ize9N_5geyu_Pt=0fAo2asIMN5G>P^m>D;Mt|Bt6o*s1KPyLXOcGe^NEPLPD{Fz z_O{*oS)Rpxr|sA0x};R9wXMrlo7di?N)3&{<`)4Hpx;Xv%~*rW#&E4lZTbWWtbeq^ z6nW$q8Jq>)BzV1H=iczCKLJ+|75se$$37CEMu%fffVXLsA}K!1WYtjh26pERJOzBx z2=&DGf+qcV+A_E5J@5LQ53HnzqTjFquV(z&v3T@SxBV(8>u2Aqutv`0}uo zXt$K-&x0Fx&uL(`aE^nc;|9d)0e68!Z8hnD+E6QiREXv09hUMG{%|C4IOsxS_A`Wn zgXYUt(-gp-SUUfClywbAFz1C+vdL|qFObWwZYDsxVxSK7S%xx-NCkVg8`lenJWBN5 z$7uaqNNePFCL_fEB<1j0I#J=BHMTWVTWAib0s{jlaSQV_p7YKQcD|Vo9GCifVru>7 zwsl3TpS0Fe$CUs0dIO!xe9qE4lREB*D5LC?6vioe4S|9S literal 0 HcmV?d00001 diff --git a/euscanwww/media/img/python.png b/euscanwww/media/img/python.png new file mode 100644 index 0000000000000000000000000000000000000000..51c33850faacba87453f1f71ede4bb989048260d GIT binary patch literal 3140 zcmV-K47>A*P)v$Jz~ujll``_As{9j{TO_K}`B^Uk^b|K~i< zbDsAM{2v$bNe%SrU-|MbE#x63I4BUe3Fy%1b~Lj>P|%toA;gc7`nC6u|LO22HSbLk zIDGh+Io>hzB`M6KQ54+L9MVpulGxj{nK=n}dH7 z1a5uoD?e{o_IFhnY_c7P?%qD~T|MM-ISj*y8)==i)`VfmY^6e}SfDUIMi@m1X}p4P zpML-Qe_s5V5*Ym4(Z{sb-?uE=*gmkEzO9=vr9lvccwvO^heS%DltK!DAqBQ6aV!G? zs3>Ik%4J5bjUc3WXH&WTo|7k!h3mm$+-QfrPad;X=>EIoq|$dCIArYIwT)+=I>@gc z7~tAeg>%CN{2(HTBEm=!L<&EQXm|lt*C&b;DaWFxryD5+rRnLus?+$Oc=6P`>meZ5 zZn97!zjQy)H!!#-YRhIhu)CjpTME;V{QBWNn1)wbb}Z9E z2>FHefCn&dyo>AtO(v602?3YKXXa|IPR?RV3Fuf`d|>Xo7Jw#<6dA`Nlg%(YTe;ocSN;R=N2RKP#=NyM9X> zjcEuBLlS9)*7H}(JP4gIa9^j4FUq^_w*YD7wd+F)!!ZhRp z0zwETN;RTr-Pl(qF!zO<>EDN7LHV-*Rl*c;KN2MZTjWzt{nj2Np(} z)~b2)i60e)l*~4K3gs#@HJ6U81BvySBC@pP)urP=XOEb9_0RMRr78YsIU-94WPSZL zVB3L%2kGw2Q}Y6XFq+5AQajfgBBh8TMWhrcO{f%M6cL7sn(H$@JxdU&Rd+AH>5k}A zyC0Z4T%)kTdj_H}N@)!KviUiOc?#kz*TqaGV;^2Jlqax?87HRnFN*0%u zT*e{oSj?2B@jcJDy=%Atkn7q5C=gamK-i!?K+(1No*1y=k=C*1OlaVdBMySWzWz-@ zO38H9<@AS>H2h#yFt#blrYvkzVhDkVQyo_F0V%*V1itTaZTQ1b2qvBweC_W1roEn% z?RN+ZfW2^%$R*Xb8Pm?_(68@bmVlKuI#r0sWi!mwJWhQui5INA>ZT#-$~j~bQ_xD` zdmakaLZI1toq?9S6OGobhQMfxl zwC~pa&(w0AgIS{KnCxN#L?8^>HuO`trut5N6X&yE##=xj5=Kd&8J(J;H`9ZZ0u?Qt z*)k-3`7ByR3}1XNDi^LBK&3Z3{dP~LBDG$fMAi=UUHxOZ+d9wQA*C<}5BzSUf7ioV zlnY@QgtJU915_Q`hy#dp=mf?V5b&!TicWi(AhCHv3c_UwZ0yJYn#=E<^{b_#y|sPv ztt0#Yd1uCSA6N}|tJtXyy?Nj%whTTYoNR9zRfk|AcHZU0`vAfsrWwOEJ@QKk44*va z?tc8MV{U!67m&7TEb)P+vrdj&jjE-hy|-uh&ELB7_&xcJchq+7e@3UXn}m?7C%8h| zn08JGA>uF@m6o@AfN%n8KZU3Qx%&u$M*Oowso7-lY^UoprAGlAOETM7SeZ*%XswyN z`l0U_{-rPO`@#O+ZJ%*(yZ`yD5Hdb|SlM@C(V$(3Tu}A+d2Zz+2n*nk#H$`mBq+N; zYkYSWKv%|?yTvdU4gI!K(c^BtO3KbGnL1^gRA;6MqbU8zz*{4RVDI3eKTHW>#;c_h z@Qb}bM-W_xU@~5D<;C$`dvTriLDe9t(V7I#iO~sKGd+1(0~cG9x`jKS^$CPHHZwIr z@3x(!ECV+&Bbmf_&#eP6&^fXr*SR^e(pyZ_Omg_N4yK@S5$f-NcR2>RUNO1}{VJ96 zgaH1twQ9jhJoM7@r-4gTV;==N3hBzFu+6xMO!9dZDGlHlVY`#*HxVXafk-9lK>b}9 z|2h=E4UG$++<14^qap*w2ByZ&10di;E9NC0rxDKvuKS(QD?@6_z@XgR)wVdxYyh!+ z2`g4<#VhU&L-9MY4KEsX-QsKqG$WT!E1+mh@vo~A82XoQ{NwJ&zxsu#(c#az^{U&^ zy(wkc_8fs)sW5*TCd|YE9jLqt)BhCPGy<$X5bL~bXquwTfxVUK@$-~RV-n5t_a9?H zXk0etMM3m=X&Jv?EloXBEls5sRnMO^!U7}|{{c!bEkuynw{l#+fvbpmb&LydzZ@bM z%ldqMas9FcKK$Ve9`Jhuj~w{}Vat62nOoeZJ6rx60LrgG?c6f2n~M7Eb^hnn%WFUs zNF&~1%QVAWE?tAz{OgSw%EhZ~XzgmrZ`}Je8jE|cdg>%ZPAylLdI*g_7DpHqOXI&L z3|#_u?Tcrv6U!}ClS~CdZkeN+1lW1Bgj2OIHeg|r2R+zC1HvT3=Gf?QlUT?xZePnfSqLj3?u#lR2FhT_)dN-Gszy`nNCf?l0`)z=dch#a9pXi=Vg&U ztn?q5Ovsr@n`UVwbux_Lr{}q}=N2}Ka5O)1^^De0T^NRend(N`n__dZx5TB@Lxe@O zGRD}*SuULUp&lK1UleD;;$MA_7hn1@7l<9U(NZ?mP0A%#B&!|jO~-BO5=SP9N>4w` zUB7&QgMHof#e)jc*$q0A$_m4>2!a65t?62=JU8ETg~ETI<&D4m9kMVmg6O4Pn{kp6pbXV<`1ws&oyJLAx1TR2{T>-jXM%8XwgW%#Z4 z7<%Jft|cqmT;1l%H$!N%tg_6?e_R4hF=*Ya!Ak z(*(cFwZi%cw2DkXr(1xxf;XAF;9NpLwGe0};U~a7)_$qJX#y*W!9quGz36KG617gCg5iP0000Categories
  • Herds
  • Maintainers
  • -
  • World
  • +
  • Scan World
  • +
  • Statistics
  • +
  • ---
  • -
  • About
  • +
  • About
  • {% endblock %} {% endblock %} diff --git a/euscanwww/templates/euscan/_package_bar.html b/euscanwww/templates/euscan/_package_bar.html new file mode 100644 index 0000000..b9fc03f --- /dev/null +++ b/euscanwww/templates/euscan/_package_bar.html @@ -0,0 +1,9 @@ +{% load mul %} +{% load sub %} +{% load div %} + +
    +
    +
    +
    +
    diff --git a/euscanwww/templates/euscan/_package_cols.html b/euscanwww/templates/euscan/_package_cols.html new file mode 100644 index 0000000..9d49f49 --- /dev/null +++ b/euscanwww/templates/euscan/_package_cols.html @@ -0,0 +1,24 @@ +{% load packages %} +{% load mul %} +{% load sub %} +{% load div %} + +{{ infos.n_packaged }} +{% if infos.n_overlay == 0 or infos.n_overlay <= infos.n_packaged %} + +{% else %}{% if infos.n_overlay < infos.n_packaged %} + +{% else %} + +{% endif %}{% endif %} + {{ infos.n_overlay }} + +{% if infos.n_versions == infos.n_packaged|add:infos.n_overlay %} + +{% else %}{% if infos.n_versions < infos.n_packaged|add:infos.n_overlay|mul:2 %} + +{% else %} + +{% endif %}{% endif %} +{{ infos.n_versions|sub:infos.n_packaged|sub:infos.n_overlay }} + diff --git a/euscanwww/templates/euscan/_packages.html b/euscanwww/templates/euscan/_packages.html index 27ebb23..4215a84 100644 --- a/euscanwww/templates/euscan/_packages.html +++ b/euscanwww/templates/euscan/_packages.html @@ -1,28 +1,22 @@ -{% load sub %} -{% load mul %} +{% load packages %} - + + {% for package in packages %} - {% if package.n_versions == package.n_packaged %} - - {% else %}{% if package.n_versions < package.n_packaged|mul:2 %} - - {% else %} - - {% endif %}{% endif %} + - - + {% package_cols package %} {% endfor %} diff --git a/euscanwww/templates/euscan/about.html b/euscanwww/templates/euscan/about.html new file mode 100644 index 0000000..8a6cbe7 --- /dev/null +++ b/euscanwww/templates/euscan/about.html @@ -0,0 +1,37 @@ +{% extends "_base.html" %} + +{% block content %} +

    What's euscan ?

    +

    +Euscan is both a tool to check if an ebuild is outdated (app-portage/euscan) and a web interface. +

    +

    +This web interface allow you to browse the portage tree, and find outdated ebuilds. It is designed to help maintainers monitor their packages and bump them. +

    +

    +euscan code source is available at http://git.iksaif.net/?p=euscan.git;a=summary. +

    +

    +This site is not an official Gentoo website. +

    + +

    + Copyright (C) 2011 Corentin Chary +

    + +

    + Powered by: + + Linux Kernel + + + Gentoo Linux + + + Django + + + Python + +

    +{% endblock %} diff --git a/euscanwww/templates/euscan/categories.html b/euscanwww/templates/euscan/categories.html index 62e61d6..30f413a 100644 --- a/euscanwww/templates/euscan/categories.html +++ b/euscanwww/templates/euscan/categories.html @@ -1,7 +1,6 @@ {% extends "euscan/_datatable.html" %} -{% load sub %} -{% load mul %} +{% load packages %} {% block title %} {{ block.super }} - categories @@ -9,24 +8,22 @@ {% block content %}

    Categories

    +
    PackageEbuildsGentooOverlays Unpackaged
    {{ package.category }}/{{ package.name }} + {% package_bar package %} {{ package.n_packaged }}{{ package.n_versions|sub:package.n_packaged }}
    - + + {% for category in categories %} - {% if category.n_versions == category.n_packaged %} - - {% else %}{% if category.n_versions < category.n_packaged|mul:1.5 %} - - {% else %} - - {% endif %}{% endif %} - - - + + + {% package_cols category %} {% endfor %} diff --git a/euscanwww/templates/euscan/category.html b/euscanwww/templates/euscan/category.html index ecbef56..4b80027 100644 --- a/euscanwww/templates/euscan/category.html +++ b/euscanwww/templates/euscan/category.html @@ -9,4 +9,9 @@ {% block content %}

    Category: {{ category }}

    {% packages packages %} + +

    Statistics

    +

    Current statistics

    + + {% endblock %} diff --git a/euscanwww/templates/euscan/herd.html b/euscanwww/templates/euscan/herd.html index 60bc50d..d61f082 100644 --- a/euscanwww/templates/euscan/herd.html +++ b/euscanwww/templates/euscan/herd.html @@ -9,4 +9,9 @@ {% block content %}

    Herd: {{ herd.herd }}

    {% packages packages %} + +

    Statistics

    +

    Current statistics

    + + {% endblock %} diff --git a/euscanwww/templates/euscan/herds.html b/euscanwww/templates/euscan/herds.html index 6dfbb35..f5ab5f3 100644 --- a/euscanwww/templates/euscan/herds.html +++ b/euscanwww/templates/euscan/herds.html @@ -1,7 +1,6 @@ {% extends "euscan/_datatable.html" %} -{% load sub %} -{% load mul %} +{% load packages %} {% block title %} {{ block.super }} - herds @@ -12,25 +11,20 @@
    CategoryEbuildsGentooOverlays Unpackaged
    {{ category.category }}{{ category.n_packaged }}{{ category.n_versions|sub:category.n_packaged }}
    + {{ category.category }} + {% package_bar category %} +
    - + + {% for herd in herds %} - {% if herd.n_versions == herd.n_packaged %} - - {% else %}{% if herd.n_versions < herd.n_packaged|mul:2 %} - - {% else %} - - {% endif %}{% endif %} + - - + {% package_cols herd %} {% endfor %} diff --git a/euscanwww/templates/euscan/index.html b/euscanwww/templates/euscan/index.html index 0ed40c4..1a2f471 100644 --- a/euscanwww/templates/euscan/index.html +++ b/euscanwww/templates/euscan/index.html @@ -8,12 +8,10 @@ Euscan is both a tool to check if an ebuild is outdated (app-portage/euscan) and a web interface.

    -This web interface allow you to browse the portage tree, and find outdated ebuilds. It was designed to help maintainers monitor their packages and bump them. +This web interface allow you to browse the portage tree, and find outdated ebuilds. It is designed to help maintainers monitor their packages and bump them.

    -

    -euscan code source is available at http://git.iksaif.net/?p=euscan.git;a=summary. -

    -

    Statistics

    + +

    Overview

    • Packages: {{ n_packages }}
    • Versions: {{ n_packaged }}
    • diff --git a/euscanwww/templates/euscan/maintainer.html b/euscanwww/templates/euscan/maintainer.html index 2c4c76e..3625754 100644 --- a/euscanwww/templates/euscan/maintainer.html +++ b/euscanwww/templates/euscan/maintainer.html @@ -9,4 +9,10 @@ {% block content %}

      Maintainer: {{ maintainer.name }} <{{ maintainer.email }}>

      {% packages packages %} + +

      Statistics

      +

      Current statistics

      + + + {% endblock %} diff --git a/euscanwww/templates/euscan/maintainers.html b/euscanwww/templates/euscan/maintainers.html index 569630d..bf0171f 100644 --- a/euscanwww/templates/euscan/maintainers.html +++ b/euscanwww/templates/euscan/maintainers.html @@ -1,7 +1,6 @@ {% extends "euscan/_datatable.html" %} -{% load sub %} -{% load mul %} +{% load packages %} {% block title %} {{ block.super }} - maintainers @@ -12,25 +11,20 @@
    HerdEbuildsGentooOverlays Unpackaged
    {{ herd.herds__herd }} + {% package_bar herd %} {{ herd.n_packaged }}{{ herd.n_versions|sub:herd.n_packaged }}
    - + + {% for maintainer in maintainers %} - {% if maintainer.n_versions == maintainer.n_packaged %} - - {% else %}{% if maintainer.n_versions < maintainer.n_packaged|mul:2 %} - - {% else %} - - {% endif %}{% endif %} + - - + {% package_cols maintainer %} {% endfor %} diff --git a/euscanwww/templates/euscan/package.html b/euscanwww/templates/euscan/package.html index 43cb52a..8a8acb9 100644 --- a/euscanwww/templates/euscan/package.html +++ b/euscanwww/templates/euscan/package.html @@ -17,7 +17,7 @@
    Homepage
    {% for homepage in package.homepages %} - {{ homepage }}
    +
    {{ homepage }}
    {% endfor %}
    {% endif %} diff --git a/euscanwww/templates/euscan/statistics.html b/euscanwww/templates/euscan/statistics.html new file mode 100644 index 0000000..79d5590 --- /dev/null +++ b/euscanwww/templates/euscan/statistics.html @@ -0,0 +1,13 @@ +{% extends "_base.html" %} + +{% block content %} +

    What's euscan ?

    +

    Statistics

    + +

    Current statistics

    + + + +

    All time statistics

    + +{% endblock %}
    MaintainerEbuildsGentooOverlays Unpackaged
    {{ maintainer.maintainers__name }} + {% package_bar maintainer %} {{ maintainer.n_packaged }}{{ maintainer.n_versions|sub:maintainer.n_packaged }}