euscanwww: charts, about, etc...
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
This commit is contained in:
parent
13dd433996
commit
0aba96f66f
115
euscanwww/euscan/charts.py
Normal file
115
euscanwww/euscan/charts.py
Normal file
@ -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})
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
if overlay == 'gentoo':
|
||||
package.n_packaged += 1
|
||||
else:
|
||||
package.n_overlay += 1
|
||||
if created:
|
||||
package.n_versions += 1
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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']
|
@ -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)
|
||||
|
8
euscanwww/euscan/templatetags/div.py
Normal file
8
euscanwww/euscan/templatetags/div.py
Normal file
@ -0,0 +1,8 @@
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
def div(value, arg=None):
|
||||
return value/arg
|
||||
|
||||
register.filter('div', div)
|
@ -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 }
|
||||
|
@ -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<chart>[\w\-]+).png$', 'chart'),
|
||||
(r'^world/$', 'world'),
|
||||
(r'^world/scan/$', 'world_scan'),
|
||||
(r'^categories/$', 'categories'),
|
||||
(r'^categories/(?P<category>[\w+][\w+.-]*)/view/$', 'category'),
|
||||
(r'^categories/(?P<category>[\w+][\w+.-]*)/charts/(?P<chart>[\w\-]+).png$', 'chart_category'),
|
||||
(r'^herds/$', 'herds'),
|
||||
(r'^herds/(?P<herd>[\{\}\w+.-]*)/view/$', 'herd'),
|
||||
(r'^herds/(?P<herd>[\{\}\w+.-]*)/charts/(?P<chart>[\w\-]+).png$', 'chart_herd'),
|
||||
(r'^maintainers/$', 'maintainers'),
|
||||
(r'^maintainers/(?P<maintainer_id>\d+)/view/$', 'maintainer'),
|
||||
(r'^maintainers/(?P<maintainer_id>\d+)/charts/(?P<chart>[\w\-]+).png$', 'chart_maintainer'),
|
||||
(r'^package/(?P<category>[\w+][\w+.-]*)/(?P<package>[\w+][\w+.-]*)/$', 'package'),
|
||||
)
|
||||
|
@ -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)
|
||||
|
0
euscanwww/media/charts/.keep_git
Normal file
0
euscanwww/media/charts/.keep_git
Normal file
@ -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;
|
||||
}
|
@ -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;
|
||||
|
BIN
euscanwww/media/img/django.png
Normal file
BIN
euscanwww/media/img/django.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
euscanwww/media/img/python.png
Normal file
BIN
euscanwww/media/img/python.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
@ -106,5 +106,6 @@ INSTALLED_APPS = (
|
||||
'django.contrib.admin',
|
||||
# Uncomment the next line to enable admin documentation:
|
||||
# 'django.contrib.admindocs',
|
||||
'GChartWrapper.charts'
|
||||
)
|
||||
|
||||
|
@ -25,26 +25,23 @@
|
||||
<li><a href="{% url euscan.views.categories %}">Categories</a></li>
|
||||
<li><a href="{% url euscan.views.herds %}">Herds</a></li>
|
||||
<li><a href="{% url euscan.views.maintainers %}">Maintainers</a></li>
|
||||
<li><a href="{% url euscan.views.world %}">World</a></li>
|
||||
<li><a href="{% url euscan.views.world %}">Scan World</a></li>
|
||||
<li><a href="{% url euscan.views.statistics %}">Statistics</a></li>
|
||||
<!--
|
||||
<li>---</li>
|
||||
<li><a href="#">Login</a></li>
|
||||
<li><a href="#">Register</a></li>
|
||||
-->
|
||||
<li>---</li>
|
||||
<li><a href="#">About</a></li>
|
||||
<li><a href="{% url euscan.views.about %}">About</a></li>
|
||||
{% endblock %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div id="footer">
|
||||
Powered by:
|
||||
<a href="http://kernel.org" titke="Linux Kernel">
|
||||
<img src="{{MEDIA_URL}}img/linux.png" alt="Linux" />
|
||||
</a>
|
||||
<a href="http://gentoo.org" title="Gentoo">
|
||||
<img src="{{MEDIA_URL}}img/gentoo.png" alt="Gentoo Linux" />
|
||||
</a>
|
||||
-
|
||||
Questions, Comments, Corrections ?
|
||||
Email: corentin.chary at gmail.com<br />
|
||||
Copyright (C) 2011 <strong>Corentin Chary</strong>
|
||||
</div>
|
||||
</body>
|
||||
|
9
euscanwww/templates/euscan/_package_bar.html
Normal file
9
euscanwww/templates/euscan/_package_bar.html
Normal file
@ -0,0 +1,9 @@
|
||||
{% load mul %}
|
||||
{% load sub %}
|
||||
{% load div %}
|
||||
|
||||
<div class="package_stat">
|
||||
<div class="packaged" style="width: {{ infos.n_packaged|mul:100.0|div:infos.n_versions }}%"></div>
|
||||
<div class="overlay" style="width: {{ infos.n_overlay|mul:100.0|div:infos.n_versions }}%"></div>
|
||||
<div class="upstream" style="width: {{ infos.n_versions|sub:infos.n_overlay|sub:infos.n_packaged|mul:100.0|div:infos.n_versions }}%"></div>
|
||||
</div>
|
24
euscanwww/templates/euscan/_package_cols.html
Normal file
24
euscanwww/templates/euscan/_package_cols.html
Normal file
@ -0,0 +1,24 @@
|
||||
{% load packages %}
|
||||
{% load mul %}
|
||||
{% load sub %}
|
||||
{% load div %}
|
||||
|
||||
<td>{{ infos.n_packaged }}</td>
|
||||
{% if infos.n_overlay == 0 or infos.n_overlay <= infos.n_packaged %}
|
||||
<td>
|
||||
{% else %}{% if infos.n_overlay < infos.n_packaged %}
|
||||
<td class="bad">
|
||||
{% else %}
|
||||
<td class="ugly">
|
||||
{% endif %}{% endif %}
|
||||
{{ infos.n_overlay }}
|
||||
</td>
|
||||
{% if infos.n_versions == infos.n_packaged|add:infos.n_overlay %}
|
||||
<td>
|
||||
{% else %}{% if infos.n_versions < infos.n_packaged|add:infos.n_overlay|mul:2 %}
|
||||
<td class="bad">
|
||||
{% else %}
|
||||
<td class="ugly">
|
||||
{% endif %}{% endif %}
|
||||
{{ infos.n_versions|sub:infos.n_packaged|sub:infos.n_overlay }}
|
||||
</td>
|
@ -1,28 +1,22 @@
|
||||
{% load sub %}
|
||||
{% load mul %}
|
||||
{% load packages %}
|
||||
|
||||
<table id="table" class="display">
|
||||
<thead>
|
||||
<th>Package</th>
|
||||
<th>Ebuilds</th>
|
||||
<th>Gentoo</th>
|
||||
<th>Overlays</th>
|
||||
<th>Unpackaged</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for package in packages %}
|
||||
{% if package.n_versions == package.n_packaged %}
|
||||
<tr class="gradeA">
|
||||
{% else %}{% if package.n_versions < package.n_packaged|mul:2 %}
|
||||
<tr class="gradeC">
|
||||
{% else %}
|
||||
<tr class="gradeX">
|
||||
{% endif %}{% endif %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url euscan.views.package package.category package.name %}">
|
||||
{{ package.category }}/{{ package.name }}
|
||||
</a>
|
||||
{% package_bar package %}
|
||||
</td>
|
||||
<td>{{ package.n_packaged }}</td>
|
||||
<td>{{ package.n_versions|sub:package.n_packaged }}</td>
|
||||
{% package_cols package %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
37
euscanwww/templates/euscan/about.html
Normal file
37
euscanwww/templates/euscan/about.html
Normal file
@ -0,0 +1,37 @@
|
||||
{% extends "_base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>What's euscan ?</h2>
|
||||
<p>
|
||||
Euscan is both a tool to check if an ebuild is outdated (app-portage/euscan) and a web interface.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
euscan code source is available at <a href="http://git.iksaif.net/?p=euscan.git;a=summary">http://git.iksaif.net/?p=euscan.git;a=summary</a>.
|
||||
</p>
|
||||
<p>
|
||||
<em>This site is not an official Gentoo website.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Copyright (C) 2011 <strong>Corentin Chary</strong>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Powered by:
|
||||
<a href="http://kernel.org" titke="Linux Kernel">
|
||||
<img src="{{MEDIA_URL}}img/linux.png" alt="Linux Kernel" />
|
||||
</a>
|
||||
<a href="http://gentoo.org" title="Gentoo">
|
||||
<img src="{{MEDIA_URL}}img/gentoo.png" alt="Gentoo Linux" />
|
||||
</a>
|
||||
<a href="http://www.djangoproject.com/" title="Django">
|
||||
<img src="{{MEDIA_URL}}img/django.png" alt="Django" />
|
||||
</a>
|
||||
<a href="http://python.org" title="Python">
|
||||
<img src="{{MEDIA_URL}}img/python.png" alt="Python" />
|
||||
</a>
|
||||
</p>
|
||||
{% endblock %}
|
@ -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 %}
|
||||
<h2>Categories</h2>
|
||||
|
||||
<table id="table" class="display">
|
||||
<thead>
|
||||
<th>Category</th>
|
||||
<th>Ebuilds</th>
|
||||
<th>Gentoo</th>
|
||||
<th>Overlays</th>
|
||||
<th>Unpackaged</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for category in categories %}
|
||||
{% if category.n_versions == category.n_packaged %}
|
||||
<tr class="gradeA">
|
||||
{% else %}{% if category.n_versions < category.n_packaged|mul:1.5 %}
|
||||
<tr class="gradeC">
|
||||
{% else %}
|
||||
<tr class="gradeX">
|
||||
{% endif %}{% endif %}
|
||||
<td><a href="{% url euscan.views.category category.category %}">{{ category.category }}</a></td>
|
||||
<td>{{ category.n_packaged }}</td>
|
||||
<td>{{ category.n_versions|sub:category.n_packaged }}</td>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url euscan.views.category category.category %}">{{ category.category }}</a>
|
||||
{% package_bar category %}
|
||||
</td>
|
||||
{% package_cols category %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
@ -9,4 +9,9 @@
|
||||
{% block content %}
|
||||
<h2>Category: {{ category }}</h2>
|
||||
{% packages packages %}
|
||||
|
||||
<h3>Statistics</h2>
|
||||
<h4>Current statistics</h4>
|
||||
<img src="{% url euscan.views.chart_category category 'pie-versions' %}" />
|
||||
<img src="{% url euscan.views.chart_category category 'pie-packages' %}" />
|
||||
{% endblock %}
|
||||
|
@ -9,4 +9,9 @@
|
||||
{% block content %}
|
||||
<h2>Herd: {{ herd.herd }}</h2>
|
||||
{% packages packages %}
|
||||
|
||||
<h3>Statistics</h2>
|
||||
<h4>Current statistics</h4>
|
||||
<img src="{% url euscan.views.chart_herd herd.herd 'pie-versions' %}" />
|
||||
<img src="{% url euscan.views.chart_herd herd.herd 'pie-packages' %}" />
|
||||
{% endblock %}
|
||||
|
@ -1,7 +1,6 @@
|
||||
{% extends "euscan/_datatable.html" %}
|
||||
|
||||
{% load sub %}
|
||||
{% load mul %}
|
||||
{% load packages %}
|
||||
|
||||
{% block title %}
|
||||
{{ block.super }} - herds
|
||||
@ -12,25 +11,20 @@
|
||||
<table id="table" class="display">
|
||||
<thead>
|
||||
<th>Herd</th>
|
||||
<th>Ebuilds</th>
|
||||
<th>Gentoo</th>
|
||||
<th>Overlays</th>
|
||||
<th>Unpackaged</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for herd in herds %}
|
||||
{% if herd.n_versions == herd.n_packaged %}
|
||||
<tr class="gradeA">
|
||||
{% else %}{% if herd.n_versions < herd.n_packaged|mul:2 %}
|
||||
<tr class="gradeC">
|
||||
{% else %}
|
||||
<tr class="gradeX">
|
||||
{% endif %}{% endif %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url euscan.views.herd herd.herds__herd %}">
|
||||
{{ herd.herds__herd }}
|
||||
</a>
|
||||
{% package_bar herd %}
|
||||
</td>
|
||||
<td>{{ herd.n_packaged }}</td>
|
||||
<td>{{ herd.n_versions|sub:herd.n_packaged }}</td>
|
||||
{% package_cols herd %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
@ -8,12 +8,10 @@
|
||||
Euscan is both a tool to check if an ebuild is outdated (app-portage/euscan) and a web interface.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
euscan code source is available at <a href="http://git.iksaif.net/?p=euscan.git;a=summary">http://git.iksaif.net/?p=euscan.git;a=summary</a>.
|
||||
</p>
|
||||
<h2>Statistics</h2>
|
||||
|
||||
<h2>Overview</h2>
|
||||
<ul>
|
||||
<li>Packages: {{ n_packages }}</li>
|
||||
<li>Versions: {{ n_packaged }}</li>
|
||||
|
@ -9,4 +9,10 @@
|
||||
{% block content %}
|
||||
<h2>Maintainer: {{ maintainer.name }} <{{ maintainer.email }}></h2>
|
||||
{% packages packages %}
|
||||
|
||||
<h3>Statistics</h2>
|
||||
<h4>Current statistics</h4>
|
||||
<img src="{% url euscan.views.chart_maintainer maintainer.id 'pie-versions' %}" />
|
||||
<img src="{% url euscan.views.chart_maintainer maintainer.id 'pie-packages' %}" />
|
||||
|
||||
{% endblock %}
|
||||
|
@ -1,7 +1,6 @@
|
||||
{% extends "euscan/_datatable.html" %}
|
||||
|
||||
{% load sub %}
|
||||
{% load mul %}
|
||||
{% load packages %}
|
||||
|
||||
{% block title %}
|
||||
{{ block.super }} - maintainers
|
||||
@ -12,25 +11,20 @@
|
||||
<table id="table" class="display">
|
||||
<thead>
|
||||
<th>Maintainer</th>
|
||||
<th>Ebuilds</th>
|
||||
<th>Gentoo</th>
|
||||
<th>Overlays</th>
|
||||
<th>Unpackaged</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for maintainer in maintainers %}
|
||||
{% if maintainer.n_versions == maintainer.n_packaged %}
|
||||
<tr class="gradeA">
|
||||
{% else %}{% if maintainer.n_versions < maintainer.n_packaged|mul:2 %}
|
||||
<tr class="gradeC">
|
||||
{% else %}
|
||||
<tr class="gradeX">
|
||||
{% endif %}{% endif %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url euscan.views.maintainer maintainer.maintainers__id %}">
|
||||
{{ maintainer.maintainers__name }}
|
||||
</a>
|
||||
{% package_bar maintainer %}
|
||||
</td>
|
||||
<td>{{ maintainer.n_packaged }}</td>
|
||||
<td>{{ maintainer.n_versions|sub:maintainer.n_packaged }}</td>
|
||||
{% package_cols maintainer %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<dt>Homepage</dt>
|
||||
<dd>
|
||||
{% for homepage in package.homepages %}
|
||||
<a href="{{ homepage }}">{{ homepage }}<br />
|
||||
<a href="{{ homepage }}">{{ homepage }}</a><br />
|
||||
{% endfor %}
|
||||
</dd>
|
||||
{% endif %}
|
||||
|
13
euscanwww/templates/euscan/statistics.html
Normal file
13
euscanwww/templates/euscan/statistics.html
Normal file
@ -0,0 +1,13 @@
|
||||
{% extends "_base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2>What's euscan ?</h2>
|
||||
<h2>Statistics</h2>
|
||||
|
||||
<h3>Current statistics</h3>
|
||||
<img src="{% url euscan.views.chart 'pie-versions' %}" />
|
||||
<img src="{% url euscan.views.chart 'pie-packages' %}" />
|
||||
|
||||
<h3>All time statistics</h3>
|
||||
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user