euscanwww: charts, about, etc...

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
This commit is contained in:
Corentin Chary 2011-04-25 22:27:32 +02:00
parent 13dd433996
commit 0aba96f66f
30 changed files with 504 additions and 121 deletions

115
euscanwww/euscan/charts.py Normal file
View 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})

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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']

View File

@ -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)

View File

@ -0,0 +1,8 @@
from django import template
register = template.Library()
def div(value, arg=None):
return value/arg
register.filter('div', div)

View File

@ -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 }

View File

@ -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'),
)

View File

@ -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)

View File

View 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;
}

View File

@ -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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -106,5 +106,6 @@ INSTALLED_APPS = (
'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'GChartWrapper.charts'
)

View File

@ -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>

View 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>

View 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>

View File

@ -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>

View 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 %}

View File

@ -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>

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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>

View File

@ -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>

View File

@ -9,4 +9,10 @@
{% block content %}
<h2>Maintainer: {{ maintainer.name }} &lt{{ maintainer.email }}&gt</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 %}

View File

@ -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>

View File

@ -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 %}

View 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 %}