euscanwww: euscan -> djeuscan
Signed-off-by: Corentin Chary <corentincj@iksaif.net>
This commit is contained in:
0
euscanwww/djeuscan/__init__.py
Normal file
0
euscanwww/djeuscan/__init__.py
Normal file
19
euscanwww/djeuscan/admin.py
Normal file
19
euscanwww/djeuscan/admin.py
Normal file
@ -0,0 +1,19 @@
|
||||
from models import *
|
||||
from django.contrib import admin
|
||||
|
||||
admin.site.register(Herd)
|
||||
admin.site.register(Maintainer)
|
||||
|
||||
class PackageAdmin(admin.ModelAdmin):
|
||||
search_fields = ('category', 'name')
|
||||
admin.site.register(Package, PackageAdmin)
|
||||
|
||||
admin.site.register(Version)
|
||||
admin.site.register(VersionLog)
|
||||
admin.site.register(EuscanResult)
|
||||
|
||||
admin.site.register(Log)
|
||||
admin.site.register(WorldLog)
|
||||
admin.site.register(CategoryLog)
|
||||
admin.site.register(HerdLog)
|
||||
admin.site.register(MaintainerLog)
|
0
euscanwww/djeuscan/api/__init__.py
Normal file
0
euscanwww/djeuscan/api/__init__.py
Normal file
50
euscanwww/djeuscan/api/emitters.py
Normal file
50
euscanwww/djeuscan/api/emitters.py
Normal file
@ -0,0 +1,50 @@
|
||||
from piston.emitters import Emitter, XMLEmitter
|
||||
|
||||
class EuscanXMLEmitter(XMLEmitter):
|
||||
_parent = []
|
||||
_known_parents = {
|
||||
'vlog' : 'version',
|
||||
'herds' : 'herd',
|
||||
'maintainers' : 'maintainer',
|
||||
'packaged' : 'version',
|
||||
'upstream' : 'version',
|
||||
'packages' : 'package',
|
||||
'categories' : 'category'
|
||||
}
|
||||
|
||||
def _push_parent(self, parent):
|
||||
self._parent.append(parent)
|
||||
|
||||
def _pop_parent(self):
|
||||
if self._parent:
|
||||
return self._parent.pop()
|
||||
else:
|
||||
return None
|
||||
|
||||
def _current_parent(self):
|
||||
if self._parent:
|
||||
return self._parent[-1]
|
||||
else:
|
||||
return None
|
||||
|
||||
def _name_from_parent(self):
|
||||
return self._known_parents.get(self._current_parent(), 'resource')
|
||||
|
||||
def _to_xml(self, xml, data):
|
||||
def recurse(name, xml, item):
|
||||
attrs = {}
|
||||
xml.startElement(name, attrs)
|
||||
self._push_parent(name)
|
||||
self._to_xml(xml, item)
|
||||
self._pop_parent()
|
||||
xml.endElement(name)
|
||||
|
||||
if isinstance(data, (list, tuple)):
|
||||
for item in data:
|
||||
name = self._name_from_parent()
|
||||
recurse(name, xml, item)
|
||||
elif isinstance(data, dict):
|
||||
for key, value in data.iteritems():
|
||||
recurse(key, xml, value)
|
||||
else:
|
||||
super(EuscanXMLEmitter, self)._to_xml(xml, data)
|
196
euscanwww/djeuscan/api/handlers.py
Normal file
196
euscanwww/djeuscan/api/handlers.py
Normal file
@ -0,0 +1,196 @@
|
||||
from piston.handler import AnonymousBaseHandler, BaseHandler
|
||||
from piston.utils import rc, HttpStatusCode
|
||||
|
||||
from django.db.models import Sum, Max
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.forms.models import model_to_dict
|
||||
|
||||
from djeuscan.models import Version, Package, Herd, Maintainer, EuscanResult, VersionLog
|
||||
from djeuscan.forms import WorldForm, PackagesForm
|
||||
|
||||
# replace default XMLEmitter with ours
|
||||
from piston.emitters import Emitter
|
||||
from emitters import EuscanXMLEmitter
|
||||
Emitter.register('xml', EuscanXMLEmitter, 'text/xml; charset=utf-8')
|
||||
|
||||
def xint(i):
|
||||
try:
|
||||
return int(i)
|
||||
except:
|
||||
return 0
|
||||
|
||||
def renameFields(vqs, fields):
|
||||
ret = []
|
||||
for n in vqs:
|
||||
for tr in fields:
|
||||
if tr[0] in n:
|
||||
n[tr[1]] = n[tr[0]]
|
||||
del n[tr[0]]
|
||||
ret.append(n)
|
||||
return ret
|
||||
|
||||
class catch_and_return(object):
|
||||
def __init__(self, err, response):
|
||||
self.err = err
|
||||
self.response = response
|
||||
|
||||
def __call__(self, fn):
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return fn(*args, **kwargs)
|
||||
except self.err:
|
||||
return self.response
|
||||
return wrapper
|
||||
|
||||
# /api/1.0/
|
||||
class RootHandler(AnonymousBaseHandler):
|
||||
allowed_methods = ('GET',)
|
||||
|
||||
def read(self, request):
|
||||
return {'api-version': '1.0'}
|
||||
|
||||
# /api/1.0/statistics
|
||||
class StatisticsHandler(AnonymousBaseHandler):
|
||||
allowed_methods = ('GET',)
|
||||
|
||||
def read(self, request):
|
||||
data = {}
|
||||
data['n_packaged'] = xint(Package.objects.aggregate(Sum('n_packaged'))['n_packaged__sum'])
|
||||
data['n_overlay'] = xint(Package.objects.aggregate(Sum('n_overlay'))['n_overlay__sum'])
|
||||
data['n_versions'] = xint(Package.objects.aggregate(Sum('n_versions'))['n_versions__sum'])
|
||||
data['n_upstream'] = data['n_versions'] - data['n_packaged'] - data['n_overlay']
|
||||
data['n_packages'] = Package.objects.count()
|
||||
data['n_herds'] = Herd.objects.count()
|
||||
data['n_maintainers'] = Maintainer.objects.count()
|
||||
data['last_scan'] = EuscanResult.objects.get(id=EuscanResult.objects.aggregate(Max('id'))['id__max']).datetime
|
||||
|
||||
return data
|
||||
|
||||
# /api/1.0/maintainers
|
||||
class MaintainersHandler(AnonymousBaseHandler):
|
||||
allowed_methods = ('GET',)
|
||||
|
||||
def read(self, request):
|
||||
maintainers = Package.objects.filter(maintainers__isnull=False)
|
||||
maintainers = maintainers.values('maintainers__id', 'maintainers__name', 'maintainers__email')
|
||||
maintainers = maintainers.annotate(n_packaged=Sum('n_packaged'),
|
||||
n_overlay=Sum('n_overlay'),
|
||||
n_versions=Sum('n_versions'))
|
||||
|
||||
maintainers = renameFields(maintainers, [('maintainers__id', 'id'),
|
||||
('maintainers__name', 'name'),
|
||||
('maintainers__email', 'email')])
|
||||
return { 'maintainers' : maintainers }
|
||||
|
||||
# /api/1.0/herds
|
||||
class HerdsHandler(AnonymousBaseHandler):
|
||||
allowed_methods = ('GET',)
|
||||
|
||||
def read(self, request):
|
||||
# FIXME: optimize the query, it uses 'LEFT OUTER JOIN' instead of 'INNER JOIN'
|
||||
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'))
|
||||
|
||||
herds = renameFields(herds, [('herds__herd', 'herd')])
|
||||
return { 'herds' : herds }
|
||||
|
||||
# /api/1.0/categories
|
||||
class CategoriesHandler(AnonymousBaseHandler):
|
||||
allowed_methods = ('GET',)
|
||||
|
||||
def read(self, request):
|
||||
categories = Package.objects.values('category')
|
||||
categories = categories.annotate(n_packaged=Sum('n_packaged'),
|
||||
n_overlay=Sum('n_overlay'),
|
||||
n_versions=Sum('n_versions'))
|
||||
|
||||
return { 'categories' : categories }
|
||||
|
||||
# /api/1.0/packages/by-maintainer/
|
||||
# /api/1.0/packages/by-category/
|
||||
# /api/1.0/packages/by-herd/
|
||||
class PackagesHandler(AnonymousBaseHandler):
|
||||
allowed_methods = ('GET',)
|
||||
fields = ('category', 'name', 'n_packaged', 'n_overlay', 'n_versions',
|
||||
('last_version_gentoo', ('version',)),
|
||||
('last_version_overlay', ('version',)),
|
||||
('last_version_upstream', ('version',)))
|
||||
model = Package
|
||||
|
||||
@catch_and_return(ObjectDoesNotExist, rc.NOT_FOUND)
|
||||
def read(self, request, **kwargs):
|
||||
data = {}
|
||||
|
||||
if 'category' in kwargs:
|
||||
packages = Package.objects.filter(category=kwargs['category'])
|
||||
data = { 'category' : kwargs['category'] }
|
||||
elif 'herd' in kwargs:
|
||||
herd = Herd.objects.get(herd=kwargs['herd'])
|
||||
packages = Package.objects.filter(herds__id=herd.id)
|
||||
data = { 'herd' : herd }
|
||||
elif 'maintainer_id' in kwargs:
|
||||
maintainer = Maintainer.objects.get(id=kwargs['maintainer_id'])
|
||||
packages = Package.objects.filter(maintainers__id=maintainer.id)
|
||||
data = { 'maintainer' : maintainer }
|
||||
|
||||
packages = packages.select_related('last_version_gentoo', 'last_version_overlay', 'last_version_upstream')
|
||||
data['packages'] = packages
|
||||
|
||||
if not data:
|
||||
return rc.NOT_FOUND
|
||||
|
||||
return data
|
||||
|
||||
# /api/1.0/package/
|
||||
class PackageHandler(AnonymousBaseHandler):
|
||||
allowed_methods = ('GET',)
|
||||
|
||||
@catch_and_return(ObjectDoesNotExist, rc.NOT_FOUND)
|
||||
def read(self, request, category, package):
|
||||
package = Package.objects.get(category=category, name=package)
|
||||
package.homepages = package.homepage.split(' ')
|
||||
versions = Version.objects.filter(package=package)
|
||||
log = EuscanResult.objects.filter(package=package).order_by('-datetime')[:1]
|
||||
log = log[0] if log else None
|
||||
vlog = VersionLog.objects.filter(package=package).order_by('-id')
|
||||
|
||||
herds = []
|
||||
for herd in package.herds.all():
|
||||
herds.append(model_to_dict(herd, ['herd']))
|
||||
|
||||
maintainers = []
|
||||
for maintainer in package.maintainers.all():
|
||||
maintainers.append(model_to_dict(maintainer, ['name', 'email']))
|
||||
|
||||
version_log = []
|
||||
for v in vlog:
|
||||
v = model_to_dict(v, ['version', 'revision', 'slot', 'overlay', 'datetime', 'action'])
|
||||
if v['action'] == VersionLog.VERSION_ADDED:
|
||||
v['action'] = 'added'
|
||||
if v['action'] == VersionLog.VERSION_REMOVED:
|
||||
v['action'] = 'removed'
|
||||
version_log.append(v)
|
||||
|
||||
upstream = []
|
||||
packaged = []
|
||||
for version in versions:
|
||||
unpackaged = not version.packaged
|
||||
version = model_to_dict(version, ['version', 'revision', 'slot', 'overlay', 'urls'])
|
||||
if unpackaged:
|
||||
upstream.append(version)
|
||||
else:
|
||||
packaged.append(version)
|
||||
|
||||
package = model_to_dict(package, ['category', 'name', 'description',
|
||||
'homepage'])
|
||||
package['herds'] = herds
|
||||
package['maintainers'] = maintainers
|
||||
package['packaged'] = packaged
|
||||
package['upstream'] = upstream
|
||||
package['vlog'] = version_log
|
||||
if log:
|
||||
package['log'] = model_to_dict(log, ['result', 'datetime'])
|
||||
|
||||
return package
|
27
euscanwww/djeuscan/api/urls.py
Normal file
27
euscanwww/djeuscan/api/urls.py
Normal file
@ -0,0 +1,27 @@
|
||||
from django.conf.urls.defaults import *
|
||||
|
||||
from piston.resource import Resource
|
||||
from handlers import *
|
||||
|
||||
root_handler = Resource(handler=RootHandler)
|
||||
statistics_handler = Resource(handler=StatisticsHandler)
|
||||
herds_handler = Resource(handler=HerdsHandler)
|
||||
categories_handler = Resource(handler=CategoriesHandler)
|
||||
maintainers_handler = Resource(handler=MaintainersHandler)
|
||||
packages_handler = Resource(handler=PackagesHandler)
|
||||
package_handler = Resource(handler=PackageHandler)
|
||||
|
||||
urlpatterns = patterns('djeuscan.api.views',
|
||||
url(r'^1.0/statistics\.(?P<emitter_format>.+)$', statistics_handler, name='api.views.statistics'),
|
||||
url(r'^1.0/herds\.(?P<emitter_format>.+)$', herds_handler, name='api.views.herds'),
|
||||
url(r'^1.0/categories\.(?P<emitter_format>.+)$', categories_handler, name='api.views.categories'),
|
||||
url(r'^1.0/maintainers\.(?P<emitter_format>.+)$', maintainers_handler, name='api.views.maintainers'),
|
||||
|
||||
url(r'^1.0/packages/by-maintainer/(?P<maintainer_id>\d+)\.(?P<emitter_format>.+)$', packages_handler, name='api.views.packages'),
|
||||
url(r'^1.0/packages/by-herd/(?P<herd>[\@\{\}\w+.-]*)\.(?P<emitter_format>.+)?$', packages_handler, name='api.views.packages'),
|
||||
url(r'^1.0/packages/by-category/(?P<category>[\w+][\w+.-]*)\.(?P<emitter_format>.+)?$', packages_handler, name='api.views.packages'),
|
||||
|
||||
url(r'^1.0/package/(?P<category>[\w+][\w+.-]*)/(?P<package>[\w+][\w+.-]*)\.(?P<emitter_format>.+)$', package_handler, name='api.views.package'),
|
||||
|
||||
url(r'^1.0/api\.(?P<emitter_format>.+)$', root_handler, name='api.views.root'),
|
||||
)
|
261
euscanwww/djeuscan/charts.py
Normal file
261
euscanwww/djeuscan/charts.py
Normal file
@ -0,0 +1,261 @@
|
||||
import os.path
|
||||
import time
|
||||
|
||||
from euscanwww import settings
|
||||
|
||||
from django.db.models import F, Sum, Max
|
||||
from djeuscan.models import Version, Package, Herd, Maintainer
|
||||
from djeuscan.models import CategoryLog
|
||||
|
||||
import rrdtool
|
||||
|
||||
import pylab
|
||||
import matplotlib
|
||||
|
||||
CHARTS_ROOT = os.path.join(settings.EUSCAN_ROOT, 'var', 'charts')
|
||||
CHARTS_URL = os.path.join(settings.EUSCAN_ROOT, 'var', '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 rrd_name(**kwargs):
|
||||
name = ""
|
||||
|
||||
if 'category' in kwargs and kwargs['category']:
|
||||
name = 'category-%s' % kwargs['category']
|
||||
elif 'herd' in kwargs and kwargs['herd']:
|
||||
name = 'herd-%d' % kwargs['herd'].id
|
||||
elif 'maintainer' in kwargs and kwargs['maintainer']:
|
||||
name = 'maintainer-%d' % kwargs['maintainer'].id
|
||||
else:
|
||||
name = 'world'
|
||||
|
||||
return name
|
||||
|
||||
def chart_name(name, **kwargs):
|
||||
name = name.replace('_', '-')
|
||||
|
||||
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
|
||||
|
||||
for kw in ('-small', '-weekly', '-monthly', '-yearly'):
|
||||
if kw in kwargs:
|
||||
name += kw
|
||||
|
||||
return name + ".png"
|
||||
|
||||
def getpackages(**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(getpackages(**kwargs).aggregate(Sum('n_packaged'))['n_packaged__sum'])
|
||||
n_overlay = xint(getpackages(**kwargs).aggregate(Sum('n_overlay'))['n_overlay__sum'])
|
||||
n_versions = xint(getpackages(**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 = getpackages(**kwargs).count()
|
||||
n_packages_uptodate_main = getpackages(**kwargs).filter(n_versions=F('n_packaged')).count()
|
||||
n_packages_uptodate_all = getpackages(**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})
|
||||
|
||||
|
||||
def rrd_path(name):
|
||||
return str(os.path.join(settings.RRD_ROOT, name + '.rrd'))
|
||||
|
||||
def rrd_create(name, start):
|
||||
path = rrd_path(name)
|
||||
if os.path.exists(path):
|
||||
return
|
||||
rrdtool.create(path, '--step', '86400',
|
||||
'--start', '%s' % int(start - 10),
|
||||
'DS:n_packages_gentoo:GAUGE:4294967295:0:U',
|
||||
'DS:n_packages_overlay:GAUGE:4294967295:0:U',
|
||||
'DS:n_packages_outdated:GAUGE:4294967295:0:U',
|
||||
'DS:n_versions_gentoo:GAUGE:4294967295:0:U',
|
||||
'DS:n_versions_overlay:GAUGE:4294967295:0:U',
|
||||
'DS:n_versions_upstream:GAUGE:4294967295:0:U',
|
||||
'RRA:AVERAGE:0.5:1:100',
|
||||
'RRA:AVERAGE:0.5:5:200',
|
||||
'RRA:AVERAGE:0.5:10:200')
|
||||
|
||||
def rrd_update(name, datetime, values):
|
||||
now = time.mktime(datetime.timetuple())
|
||||
rrd_create(name, now)
|
||||
rrdtool.update(rrd_path(name),
|
||||
'%d:%d:%d:%d:%d:%d:%d' % \
|
||||
(now, values.n_packages_gentoo, values.n_packages_overlay, values.n_packages_outdated, \
|
||||
values.n_versions_gentoo, values.n_versions_overlay, values.n_versions_upstream))
|
||||
|
||||
|
||||
"""
|
||||
[-s|--start time] [-e|--end time] [-S|--step seconds]
|
||||
[-t|--title string] [-v|--vertical-label string]
|
||||
[-w|--width pixels] [-h|--height pixels] [-j|--only-graph] [-D|--full-size-mode][-u|--upper-limit value] [-l|--lower-limit value]
|
||||
[-u|--upper-limit value] [-l|--lower-limit value] [-r|--rigid]
|
||||
[-A|--alt-autoscale]
|
||||
[-M|--alt-autoscale-max]
|
||||
[-J|--alt-autoscale-min]
|
||||
"""
|
||||
|
||||
def cached_rrd_chart(f):
|
||||
def new_f(*args, **kwds):
|
||||
if 'period' not in kwds:
|
||||
kwds['period'] = '-yearly'
|
||||
|
||||
name = chart_name(f.func_name, **kwds)
|
||||
path = os.path.join(CHARTS_ROOT, name)
|
||||
|
||||
if not chart_alive(name):
|
||||
kwds['title'] = '%s (%s)' % (f.func_name, kwds['period'])
|
||||
kwds['steps'] = kwds['period']
|
||||
kwds['vertical-label'] = f.func_name
|
||||
kwds['rrd'] = rrd_path(rrd_name(**kwds))
|
||||
kwds['path'] = path
|
||||
|
||||
kwds['end'] = 'now'
|
||||
|
||||
if kwds['period'] == '-weekly':
|
||||
kwds['start'] = 'now-4weeks'
|
||||
elif kwds['period'] == '-monthly':
|
||||
kwds['start'] = 'now-12months'
|
||||
else:
|
||||
kwds['start'] = 'now-4years'
|
||||
|
||||
if '-small' in kwds and kwds['-small']:
|
||||
kwds['width'] = '100'
|
||||
kwds['height'] = '30'
|
||||
kwds['graph-mode'] = '--only-graph'
|
||||
else:
|
||||
kwds['width'] = '500'
|
||||
kwds['height'] = '170'
|
||||
kwds['graph-mode'] = '--full-size-mode'
|
||||
|
||||
f(*args, **kwds)
|
||||
|
||||
return name
|
||||
|
||||
new_f.func_name = f.func_name
|
||||
return new_f
|
||||
|
||||
@cached_rrd_chart
|
||||
def packages(**kwargs):
|
||||
rrdtool.graph(str(kwargs['path']),
|
||||
'--imgformat', 'PNG',
|
||||
'--width', kwargs['width'],
|
||||
'--height', kwargs['height'],
|
||||
kwargs['graph-mode'],
|
||||
'--color', 'CANVAS#FFFFFF00',
|
||||
'--color', 'BACK#FFFFFF00',
|
||||
|
||||
'--start', kwargs['start'],
|
||||
'--end', kwargs['end'],
|
||||
'--vertical-label', kwargs['vertical-label'],
|
||||
'--title', kwargs['title'],
|
||||
'--lower-limit', '0',
|
||||
'DEF:n_packages_gentoo=%s:n_packages_gentoo:AVERAGE' % (kwargs['rrd']),
|
||||
'DEF:n_packages_overlay=%s:n_packages_overlay:AVERAGE' % (kwargs['rrd']),
|
||||
'DEF:n_packages_outdated=%s:n_packages_outdated:AVERAGE' % (kwargs['rrd']),
|
||||
'LINE1.25:n_packages_gentoo#008000:Gentoo',
|
||||
'LINE1.25:n_packages_overlay#0B17FD:Overlay',
|
||||
'LINE1.25:n_packages_outdated#FF0000:Outdated')
|
||||
|
||||
@cached_rrd_chart
|
||||
def versions(**kwargs):
|
||||
rrdtool.graph(str(kwargs['path']),
|
||||
'--imgformat', 'PNG',
|
||||
'--width', kwargs['width'],
|
||||
'--height', kwargs['height'],
|
||||
kwargs['graph-mode'],
|
||||
'--color', 'CANVAS#FFFFFF00',
|
||||
'--color', 'BACK#FFFFFF00',
|
||||
'--start', kwargs['start'],
|
||||
'--end', kwargs['end'],
|
||||
'--vertical-label', kwargs['vertical-label'],
|
||||
'--title', kwargs['title'],
|
||||
'--lower-limit', '0',
|
||||
'DEF:n_versions_gentoo=%s:n_versions_gentoo:AVERAGE' % (kwargs['rrd']),
|
||||
'DEF:n_versions_overlay=%s:n_versions_overlay:AVERAGE' % (kwargs['rrd']),
|
||||
'DEF:n_versions_outdated=%s:n_versions_upstream:AVERAGE' % (kwargs['rrd']),
|
||||
'LINE1.25:n_versions_gentoo#008000:Gentoo',
|
||||
'LINE1.25:n_versions_overlay#0B17FD:Overlay',
|
||||
'LINE1.25:n_versions_outdated#FF0000:Outdated')
|
||||
|
||||
|
138
euscanwww/djeuscan/feeds.py
Normal file
138
euscanwww/djeuscan/feeds.py
Normal file
@ -0,0 +1,138 @@
|
||||
from django.contrib.syndication.views import Feed, FeedDoesNotExist
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.http import Http404
|
||||
from django.utils.feedgenerator import Atom1Feed
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from djeuscan.models import Version, Package, Herd, Maintainer, VersionLog
|
||||
from djeuscan.views import *
|
||||
|
||||
class BaseFeed(Feed):
|
||||
feed_type = Atom1Feed
|
||||
author_name = 'euscan'
|
||||
item_author_name = author_name
|
||||
ttl = 3600
|
||||
|
||||
def item_title(self, vlog):
|
||||
return str(vlog)
|
||||
|
||||
def item_description(self, vlog):
|
||||
if vlog.overlay:
|
||||
txt = 'Version %s-%s [%s] of package %s ' % (vlog.version, vlog.revision,
|
||||
vlog.slot, vlog.package)
|
||||
else:
|
||||
txt = 'Version %s of package %s ' % (vlog.version, vlog.package)
|
||||
if vlog.action == vlog.VERSION_REMOVED:
|
||||
if not vlog.overlay:
|
||||
txt += 'has been removed upstream'
|
||||
else:
|
||||
txt += 'has been removed from overlay "%s"' % vlog.overlay
|
||||
if vlog.action == vlog.VERSION_ADDED:
|
||||
if not vlog.overlay:
|
||||
txt += 'has been added upstream'
|
||||
else:
|
||||
txt += 'has been added to overlay "%s"' % vlog.overlay
|
||||
|
||||
return txt
|
||||
|
||||
def item_link(self, vlog):
|
||||
kwargs = {'category' : vlog.package.category, 'package' : vlog.package.name }
|
||||
return reverse('djeuscan.views.package', kwargs=kwargs) + '#' + vlog.tag()
|
||||
|
||||
def item_pubdate(self, vlog):
|
||||
return vlog.datetime
|
||||
|
||||
def item_categories(self, vlog):
|
||||
return [vlog.package.category]
|
||||
|
||||
class GlobalFeed(BaseFeed):
|
||||
title = "euscan"
|
||||
link = "/"
|
||||
description = "Last euscan changes"
|
||||
|
||||
def categories(self):
|
||||
categories = Package.objects.values('category').distinct();
|
||||
return [ category['category'] for category in categories ]
|
||||
|
||||
def items(self):
|
||||
return VersionLog.objects.order_by('-id')[:250]
|
||||
|
||||
class PackageFeed(BaseFeed):
|
||||
feed_type = Atom1Feed
|
||||
|
||||
def get_object(self, request, category, package):
|
||||
return get_object_or_404(Package, category=category, name=package)
|
||||
|
||||
def title(self, package):
|
||||
return "%s" % package
|
||||
|
||||
def link(self, package):
|
||||
return reverse('djeuscan.views.package', args=[package.category, package.name])
|
||||
|
||||
def description(self, package):
|
||||
return package.description
|
||||
|
||||
def items(self, package):
|
||||
return VersionLog.objects.filter(package=package).order_by('-id')[:30]
|
||||
|
||||
def item_description(self, vlog):
|
||||
return ''
|
||||
|
||||
class MaintainerFeed(BaseFeed):
|
||||
feed_type = Atom1Feed
|
||||
|
||||
def get_object(self, request, maintainer_id):
|
||||
return get_object_or_404(Maintainer, id=maintainer_id)
|
||||
|
||||
def title(self, maintainer):
|
||||
return "%s" % maintainer
|
||||
|
||||
def description(self, maintainer):
|
||||
return "Last changes for %s" % maintainer
|
||||
|
||||
def link(self, maintainer):
|
||||
return reverse('djeuscan.views.maintainer', kwargs={'maintainer_id' : maintainer.id})
|
||||
|
||||
def items(self, maintainer):
|
||||
q = VersionLog.objects.filter(package__maintainers__id=maintainer.id)
|
||||
return q.order_by('-id')[:50]
|
||||
|
||||
class HerdFeed(BaseFeed):
|
||||
feed_type = Atom1Feed
|
||||
|
||||
def get_object(self, request, herd):
|
||||
return get_object_or_404(Herd, herd=herd)
|
||||
|
||||
def title(self, herd):
|
||||
return "%s" % herd
|
||||
|
||||
def description(self, herd):
|
||||
return "Last changes for %s" % herd
|
||||
|
||||
def link(self, herd):
|
||||
return reverse('djeuscan.views.herd', kwargs={'herd' : herd.herd})
|
||||
|
||||
def items(self, herd):
|
||||
q = VersionLog.objects.filter(package__herds__id=herd.id)
|
||||
return q.order_by('-id')[:100]
|
||||
|
||||
class CategoryFeed(BaseFeed):
|
||||
feed_type = Atom1Feed
|
||||
|
||||
def get_object(self, request, category):
|
||||
if not Package.objects.filter(category=category).count():
|
||||
raise FeedDoesNotExist
|
||||
return category
|
||||
|
||||
def title(self, category):
|
||||
return "%s" % category
|
||||
|
||||
def description(self, category):
|
||||
return "Last changes for %s" % category
|
||||
|
||||
def link(self, category):
|
||||
return reverse('djeuscan.views.category', args=[category])
|
||||
|
||||
def items(self, category):
|
||||
q = VersionLog.objects.filter(package__category=category)
|
||||
return q.order_by('-id')[:100]
|
7
euscanwww/djeuscan/forms.py
Normal file
7
euscanwww/djeuscan/forms.py
Normal file
@ -0,0 +1,7 @@
|
||||
from django import forms
|
||||
|
||||
class WorldForm(forms.Form):
|
||||
world = forms.FileField()
|
||||
|
||||
class PackagesForm(forms.Form):
|
||||
packages = forms.CharField(widget=forms.Textarea)
|
0
euscanwww/djeuscan/management/__init__.py
Normal file
0
euscanwww/djeuscan/management/__init__.py
Normal file
0
euscanwww/djeuscan/management/commands/__init__.py
Normal file
0
euscanwww/djeuscan/management/commands/__init__.py
Normal file
55
euscanwww/djeuscan/management/commands/list-packages.py
Normal file
55
euscanwww/djeuscan/management/commands/list-packages.py
Normal file
@ -0,0 +1,55 @@
|
||||
from optparse import make_option
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from djeuscan.models import Package
|
||||
|
||||
class Command(BaseCommand):
|
||||
_overlays = {}
|
||||
help = 'List packages'
|
||||
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--after',
|
||||
action='store',
|
||||
dest='after',
|
||||
default=False,
|
||||
help='After package'),
|
||||
make_option('--before',
|
||||
action='store',
|
||||
dest='before',
|
||||
default=False,
|
||||
help='Before package'),
|
||||
make_option('--limit',
|
||||
action='store',
|
||||
dest='limit',
|
||||
default=False,
|
||||
help='limit'),
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
after = None
|
||||
before = None
|
||||
|
||||
if options['after']:
|
||||
category, name = options['after'].split('/')
|
||||
after = Package.objects.get(category=category, name=name)
|
||||
|
||||
if options['before']:
|
||||
category, name = options['before'].split('/')
|
||||
before = Package.objects.get(category=category, name=name)
|
||||
|
||||
packages = Package.objects
|
||||
|
||||
if after or before:
|
||||
if after:
|
||||
packages = packages.filter(id__gte=after.id)
|
||||
if before:
|
||||
packages = packages.filter(id__lte=before.id)
|
||||
else:
|
||||
packages = packages.all()
|
||||
|
||||
if options['limit']:
|
||||
packages = packages[:int(options['limit'])]
|
||||
|
||||
for pkg in packages:
|
||||
self.stdout.write('%s/%s\n' % (pkg.category, pkg.name))
|
||||
self.stdout.close()
|
24
euscanwww/djeuscan/management/commands/regen-rrds.py
Normal file
24
euscanwww/djeuscan/management/commands/regen-rrds.py
Normal file
@ -0,0 +1,24 @@
|
||||
import datetime
|
||||
|
||||
from optparse import make_option
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from djeuscan.models import HerdLog, MaintainerLog, CategoryLog, WorldLog
|
||||
from djeuscan import charts
|
||||
|
||||
class Command(BaseCommand):
|
||||
_overlays = {}
|
||||
help = 'Regenerate rrd database'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
for wlog in WorldLog.objects.all():
|
||||
charts.rrd_update('world', wlog.datetime, wlog)
|
||||
|
||||
for clog in CategoryLog.objects.all():
|
||||
charts.rrd_update('category-%s' % clog.category, clog.datetime, clog)
|
||||
|
||||
for hlog in HerdLog.objects.all():
|
||||
charts.rrd_update('herd-%d' % hlog.herd.id, hlog.datetime, hlog)
|
||||
|
||||
for mlog in MaintainerLog.objects.all():
|
||||
charts.rrd_update('maintainer-%d' % mlog.maintainer.id, mlog.datetime, mlog)
|
140
euscanwww/djeuscan/management/commands/scan-metadata.py
Normal file
140
euscanwww/djeuscan/management/commands/scan-metadata.py
Normal file
@ -0,0 +1,140 @@
|
||||
import subprocess
|
||||
import portage
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
from portage import versions
|
||||
from optparse import make_option
|
||||
|
||||
from django.db.transaction import commit_on_success
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from djeuscan.models import Package, Herd, Maintainer
|
||||
|
||||
from gentoolkit.query import Query
|
||||
from gentoolkit.errors import GentoolkitFatalError
|
||||
|
||||
class Command(BaseCommand):
|
||||
_overlays = {}
|
||||
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--all',
|
||||
action='store_true',
|
||||
dest='all',
|
||||
default=False,
|
||||
help='Scan all packages'),
|
||||
make_option('--quiet',
|
||||
action='store_true',
|
||||
dest='quiet',
|
||||
default=False,
|
||||
help='Be quiet'),
|
||||
)
|
||||
args = '<package package ...>'
|
||||
help = 'Scans metadata and fills database'
|
||||
|
||||
@commit_on_success
|
||||
def handle(self, *args, **options):
|
||||
self.options = options
|
||||
|
||||
if options['all']:
|
||||
for pkg in Package.objects.all():
|
||||
self.scan('%s/%s' % (pkg.category, pkg.name), pkg)
|
||||
elif len(args):
|
||||
for package in args:
|
||||
self.scan(package)
|
||||
else:
|
||||
for package in sys.stdin.readlines():
|
||||
self.scan(package[:-1])
|
||||
|
||||
def scan(self, query=None, obj=None):
|
||||
matches = Query(query).find(
|
||||
include_masked=True,
|
||||
in_installed=False,
|
||||
)
|
||||
|
||||
if not matches:
|
||||
sys.stderr.write(self.style.ERROR("Unknown package '%s'\n" % query))
|
||||
return
|
||||
|
||||
matches = sorted(matches)
|
||||
pkg = matches.pop()
|
||||
if '9999' in pkg.version and len(matches):
|
||||
pkg = matches.pop()
|
||||
|
||||
if not obj:
|
||||
obj, created = Package.objects.get_or_create(category=pkg.category, name=pkg.name)
|
||||
else:
|
||||
created = False
|
||||
|
||||
try:
|
||||
obj.homepage = pkg.environment("HOMEPAGE")
|
||||
obj.description = pkg.environment("DESCRIPTION")
|
||||
except GentoolkitFatalError, err:
|
||||
sys.stderr.write(self.style.ERROR("Gentoolkit fatal error: '%s'\n" % str(err)))
|
||||
|
||||
if created and not self.options['quiet']:
|
||||
sys.stdout.write('+ [p] %s/%s\n' % (pkg.category, pkg.name))
|
||||
|
||||
if pkg.metadata:
|
||||
herds = dict([(herd[0], herd) for herd in pkg.metadata.herds(True)])
|
||||
maintainers = dict([(m.email, m) for m in pkg.metadata.maintainers()])
|
||||
|
||||
existing_herds = [h.herd for h in obj.herds.all()]
|
||||
new_herds = set(herds.keys()).difference(existing_herds)
|
||||
old_herds = set(existing_herds).difference(herds.keys())
|
||||
|
||||
existing_maintainers = [m.email for m in obj.maintainers.all()]
|
||||
new_maintainers = set(maintainers.keys()).difference(existing_maintainers)
|
||||
old_maintainers = set(existing_maintainers).difference(maintainers.keys())
|
||||
|
||||
for herd in obj.herds.all():
|
||||
if herd.email in old_herds:
|
||||
obj.herds.remove(herd)
|
||||
|
||||
for herd in new_herds:
|
||||
herd = self.store_herd(*herds[herd])
|
||||
obj.herds.add(herd)
|
||||
|
||||
for maintainer in obj.maintainers.all():
|
||||
if maintainer.email in old_maintainers:
|
||||
obj.maintainers.remove(maintainer)
|
||||
|
||||
for maintainer in new_maintainers:
|
||||
maintainer = maintainers[maintainer]
|
||||
maintainer = self.store_maintainer(maintainer.name, maintainer.email)
|
||||
obj.maintainers.add(maintainer)
|
||||
|
||||
obj.save()
|
||||
|
||||
def store_herd(self, name, email):
|
||||
if not name:
|
||||
name = '{nil}'
|
||||
name = name.strip("\r").strip("\n").strip("\t").strip()
|
||||
|
||||
herd, created = Herd.objects.get_or_create(herd=name)
|
||||
|
||||
if created and not self.options['quiet']:
|
||||
sys.stdout.write('+ [h] %s <%s>\n' % (name, email))
|
||||
|
||||
herd.email = email
|
||||
herd.save()
|
||||
|
||||
return herd
|
||||
|
||||
def store_maintainer(self, name, email):
|
||||
if not name:
|
||||
name = email
|
||||
if not name:
|
||||
name = '{nil}'
|
||||
|
||||
maintainer, created = Maintainer.objects.get_or_create(email=email)
|
||||
|
||||
if created:
|
||||
if not self.options['quiet']:
|
||||
sys.stdout.write('+ [m] %s <%s>\n' % (name.encode('utf-8'), email))
|
||||
|
||||
if not maintainer.name or name not in [maintainer.name, email, '{nil}']:
|
||||
maintainer.name = name
|
||||
maintainer.save()
|
||||
|
||||
return maintainer
|
299
euscanwww/djeuscan/management/commands/scan-portage.py
Normal file
299
euscanwww/djeuscan/management/commands/scan-portage.py
Normal file
@ -0,0 +1,299 @@
|
||||
import subprocess
|
||||
import portage
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
from portage import versions
|
||||
from optparse import make_option
|
||||
|
||||
from django.db.transaction import commit_on_success
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from djeuscan.models import Package, Version, VersionLog
|
||||
|
||||
class Command(BaseCommand):
|
||||
_overlays = {}
|
||||
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--all',
|
||||
action='store_true',
|
||||
dest='all',
|
||||
default=False,
|
||||
help='Scan all packages'),
|
||||
make_option('--purge-packages',
|
||||
action='store_true',
|
||||
dest='purge-packages',
|
||||
default=False,
|
||||
help='Purge old packages'),
|
||||
make_option('--purge-versions',
|
||||
action='store_true',
|
||||
dest='purge-versions',
|
||||
default=False,
|
||||
help='Purge old versions'),
|
||||
make_option('--no-log',
|
||||
action='store_true',
|
||||
dest='no-log',
|
||||
default=False,
|
||||
help='Don\'t store logs'),
|
||||
make_option('--prefetch',
|
||||
action='store_true',
|
||||
dest='prefetch',
|
||||
default=False,
|
||||
help='Prefetch all versions and packages from DB to speedup full scan process.'),
|
||||
make_option('--quiet',
|
||||
action='store_true',
|
||||
dest='quiet',
|
||||
default=False,
|
||||
help='Be quiet'),
|
||||
)
|
||||
args = '[package package ...]'
|
||||
help = 'Scans portage tree and fills database'
|
||||
|
||||
_cache = {'packages' : {}, 'versions' : {}}
|
||||
|
||||
def cache_hash_package(self, category, name):
|
||||
return '%s/%s' % (category, name)
|
||||
|
||||
def cache_store_package(self, package):
|
||||
key = self.cache_hash_package(package.category, package.name)
|
||||
self._cache['packages'][key] = package
|
||||
|
||||
def cache_get_package(self, category, name):
|
||||
return self._cache['packages'].get(self.cache_hash_package(category, name))
|
||||
|
||||
def cache_hash_version(self, category, name, version, revision, slot, overlay):
|
||||
key = '%s/%s-%s-r%s %s %s' % (category, name,
|
||||
version, revision,
|
||||
slot, overlay)
|
||||
return key
|
||||
|
||||
def cache_get_version(self, category, name, version, revision, slot, overlay):
|
||||
key = self.cache_hash_version(category, name, version, revision, slot, overlay)
|
||||
return self._cache['versions'].get(key)
|
||||
|
||||
def cache_store_version(self, version):
|
||||
key = self.cache_hash_version(version.package.category, version.package.name,
|
||||
version.version, version.revision, version.slot,
|
||||
version.overlay)
|
||||
self._cache['versions'][key] = version
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.options = options
|
||||
|
||||
if not options['quiet']:
|
||||
self.stdout.write('Scanning portage tree...\n')
|
||||
|
||||
if options['prefetch']:
|
||||
if not options['quiet']:
|
||||
self.stdout.write('Prefetching objects...')
|
||||
self.stdout.flush()
|
||||
for package in Package.objects.all():
|
||||
self.cache_store_package(package)
|
||||
for version in Version.objects.select_related('package').all():
|
||||
self.cache_store_version(version)
|
||||
if not options['quiet']:
|
||||
self.stdout.write('done\n')
|
||||
|
||||
if options['all']:
|
||||
self.scan()
|
||||
elif len(args):
|
||||
for package in args:
|
||||
self.scan(package)
|
||||
else:
|
||||
for package in sys.stdin.readlines():
|
||||
self.scan(package[:-1])
|
||||
|
||||
if options['purge-versions']:
|
||||
self.purge_versions(options)
|
||||
|
||||
if not options['quiet']:
|
||||
self.stdout.write('Done.\n')
|
||||
|
||||
def overlays(self):
|
||||
if self._overlays:
|
||||
return self._overlays
|
||||
|
||||
env = os.environ
|
||||
env['OVERLAYS_LIST'] = 'all'
|
||||
env['PRINT_COUNT_ALWAYS'] = 'never'
|
||||
|
||||
cmd = ['eix', '-!']
|
||||
|
||||
output = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env).communicate()[0]
|
||||
output = output.strip().strip('\n').split('\n')
|
||||
|
||||
overlay_re = re.compile(r'^\[(?P<key>\d+)] "(?P<name>.*?)"')
|
||||
|
||||
self._overlays = {}
|
||||
|
||||
for line in output:
|
||||
match = overlay_re.match(line)
|
||||
if not match:
|
||||
continue
|
||||
self._overlays[match.group('key')] = match.group('name')
|
||||
|
||||
return self._overlays
|
||||
|
||||
@commit_on_success
|
||||
def scan(self, query=None):
|
||||
env = os.environ
|
||||
env['MY'] = "<category>/<name>-<version>:<slot> [<overlaynum>]\n"
|
||||
|
||||
cmd = ['eix', '--format', '<availableversions:MY>', '--pure-packages', '-x']
|
||||
if query:
|
||||
cmd.extend(['--exact', query])
|
||||
|
||||
if self.options['all']:
|
||||
if not self.options['quiet']:
|
||||
self.stdout.write('Killing existing versions...')
|
||||
self.stdout.flush()
|
||||
Version.objects.filter(packaged=True).update(alive=False)
|
||||
if not self.options['quiet']:
|
||||
self.stdout.write('done\n')
|
||||
|
||||
output = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env).communicate()[0]
|
||||
output = output.strip().strip('\n')
|
||||
|
||||
if len(output) == 0:
|
||||
if not query:
|
||||
return
|
||||
if self.options['purge-packages']:
|
||||
if not self.options['quiet']:
|
||||
sys.stdout.write('- [p] %s\n' % (query))
|
||||
if '/' in query:
|
||||
cat, pkg = portage.catsplit(query)
|
||||
Package.objects.filter(category=cat, name=pkg).delete()
|
||||
else:
|
||||
Package.objects.filter(name=query).delete()
|
||||
else:
|
||||
sys.stderr.write(self.style.ERROR("Unknown package '%s'\n" % query))
|
||||
return
|
||||
|
||||
output = output.split('\n')
|
||||
packages = {}
|
||||
|
||||
line_re = re.compile(r'^(?P<cpv>.*?):(?P<slot>.*?) \[(?P<overlay>.*?)\]$')
|
||||
|
||||
package = None
|
||||
|
||||
for line in output:
|
||||
match = line_re.match(line)
|
||||
|
||||
if not match:
|
||||
continue
|
||||
|
||||
cpv = match.group('cpv')
|
||||
slot = match.group('slot')
|
||||
overlay = match.group('overlay')
|
||||
|
||||
cat, pkg, ver, rev = portage.catpkgsplit(cpv)
|
||||
|
||||
packages['%s/%s' % (cat, pkg)] = True
|
||||
|
||||
if not package or not (cat == package.category and pkg == package.name):
|
||||
package = self.store_package(cat, pkg)
|
||||
|
||||
self.store_version(package, cpv, slot, overlay)
|
||||
|
||||
if self.options['purge-packages'] and not query:
|
||||
for package in Package.objects.all():
|
||||
cp = "%s/%s" % (package.category, package.name)
|
||||
if cp not in packages:
|
||||
if not self.options['quiet']:
|
||||
sys.stdout.write('- [p] %s\n' % (package))
|
||||
package.delete()
|
||||
|
||||
def store_package(self, cat, pkg):
|
||||
created = False
|
||||
obj = self.cache_get_package(cat, pkg)
|
||||
|
||||
if not obj:
|
||||
obj, created = Package.objects.get_or_create(category=cat, name=pkg)
|
||||
self.cache_store_package(obj)
|
||||
|
||||
if created:
|
||||
if not self.options['quiet']:
|
||||
sys.stdout.write('+ [p] %s/%s\n' % (cat, pkg))
|
||||
|
||||
' Set all versions dead, then set found versions alive and delete old versions '
|
||||
if not self.options['all']:
|
||||
Version.objects.filter(package=obj, packaged=True).update(alive=False)
|
||||
|
||||
return obj
|
||||
|
||||
def store_version(self, package, cpv, slot, overlay):
|
||||
cat, pkg, ver, rev = portage.catpkgsplit(cpv)
|
||||
|
||||
overlays = self.overlays()
|
||||
|
||||
if overlay in overlays:
|
||||
overlay = overlays[overlay]
|
||||
else:
|
||||
overlay = 'gentoo'
|
||||
|
||||
created = False
|
||||
obj = self.cache_get_version(package.category, package.name, ver, rev, slot, overlay)
|
||||
if not obj:
|
||||
obj, created = Version.objects.get_or_create(package=package, slot=slot,
|
||||
revision=rev, version=ver,
|
||||
overlay=overlay)
|
||||
|
||||
obj.alive = True
|
||||
obj.packaged = True
|
||||
obj.save()
|
||||
|
||||
if created:
|
||||
self.cache_store_version(obj)
|
||||
|
||||
''' nothing to do (note: it can't be an upstream version because overlay can't be empty here) '''
|
||||
if not created:
|
||||
return
|
||||
|
||||
if not self.options['quiet']:
|
||||
sys.stdout.write('+ [v] %s \n' % (obj))
|
||||
|
||||
if overlay == 'gentoo':
|
||||
package.n_packaged += 1
|
||||
else:
|
||||
package.n_overlay += 1
|
||||
package.n_versions += 1
|
||||
package.save()
|
||||
|
||||
if self.options['no-log']:
|
||||
return
|
||||
|
||||
entry = VersionLog.objects.create(package=obj.package,
|
||||
action=VersionLog.VERSION_ADDED)
|
||||
entry.slot = obj.slot
|
||||
entry.revision = obj.revision
|
||||
entry.version = obj.version
|
||||
entry.overlay = obj.overlay
|
||||
entry.save()
|
||||
|
||||
@commit_on_success
|
||||
def purge_versions(self, options):
|
||||
' For each dead versions '
|
||||
for version in Version.objects.filter(packaged=True, alive=False):
|
||||
if version.overlay == 'gentoo':
|
||||
version.package.n_packaged -= 1
|
||||
else:
|
||||
version.package.n_overlay -= 1
|
||||
version.package.n_versions -= 1
|
||||
version.package.save()
|
||||
|
||||
if not self.options['quiet']:
|
||||
sys.stdout.write('- [v] %s\n' % (version))
|
||||
|
||||
if self.options['no-log']:
|
||||
continue
|
||||
|
||||
entry = VersionLog.objects.create(package=version.package,
|
||||
action=VersionLog.VERSION_REMOVED)
|
||||
entry.slot = version.slot
|
||||
entry.revision = version.revision
|
||||
entry.version = version.version
|
||||
entry.overlay = version.overlay
|
||||
entry.save()
|
||||
|
||||
Version.objects.filter(packaged=True, alive=False).delete()
|
||||
|
185
euscanwww/djeuscan/management/commands/scan-upstream.py
Normal file
185
euscanwww/djeuscan/management/commands/scan-upstream.py
Normal file
@ -0,0 +1,185 @@
|
||||
import subprocess
|
||||
import portage
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
from StringIO import StringIO
|
||||
from datetime import datetime
|
||||
from portage import versions
|
||||
from optparse import make_option
|
||||
|
||||
from django.db.transaction import commit_on_success
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from djeuscan.models import Package, Version, EuscanResult, VersionLog
|
||||
|
||||
class Command(BaseCommand):
|
||||
_overlays = {}
|
||||
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--all',
|
||||
action='store_true',
|
||||
dest='all',
|
||||
default=False,
|
||||
help='Scan all packages'),
|
||||
make_option('--feed',
|
||||
action='store_true',
|
||||
dest='feed',
|
||||
default=False,
|
||||
help='Read euscan output from stdin'),
|
||||
make_option('--purge-versions',
|
||||
action='store_true',
|
||||
dest='purge-versions',
|
||||
default=False,
|
||||
help='Purge old versions'),
|
||||
make_option('--quiet',
|
||||
action='store_true',
|
||||
dest='quiet',
|
||||
default=False,
|
||||
help='Be quiet'),
|
||||
)
|
||||
args = '<package package ...>'
|
||||
help = 'Scans metadata and fills database'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if options['feed']:
|
||||
self.parse_output(options, sys.stdin)
|
||||
if options['purge-versions']:
|
||||
self.purge_versions(options)
|
||||
return
|
||||
|
||||
if not options['quiet']:
|
||||
self.stdout.write('Scanning upstream...\n')
|
||||
|
||||
packages = []
|
||||
|
||||
if options['all']:
|
||||
for pkg in Package.objects.all():
|
||||
packages.append('%s/%s' % (pkg.category, pkg.name))
|
||||
elif args:
|
||||
packages = list(args)
|
||||
else:
|
||||
packages = [ package[:-1] for package in sys.stdin.readlines() ]
|
||||
|
||||
self.scan(options, packages)
|
||||
|
||||
if options['purge-versions']:
|
||||
self.purge_versions(options)
|
||||
|
||||
if not options['quiet']:
|
||||
self.stdout.write('Done.\n')
|
||||
|
||||
def scan(self, options, packages=None):
|
||||
for package in packages:
|
||||
cmd = ['euscan', package]
|
||||
|
||||
fp = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||||
output = StringIO(fp.communicate()[0])
|
||||
|
||||
self.parse_output(options, output)
|
||||
|
||||
@commit_on_success
|
||||
def parse_output(self, options, output):
|
||||
from portage.versions import _cp
|
||||
|
||||
package_re = re.compile(r'^ \* (?P<cpv>' + _cp + ') \[(?P<overlay>.*?)\]$')
|
||||
version_re = re.compile(r'^Upstream Version: (?P<ver>.*?) (?P<url>.*?)$')
|
||||
|
||||
package = None
|
||||
log = ""
|
||||
|
||||
while True:
|
||||
line = output.readline()
|
||||
if line == '':
|
||||
break
|
||||
match = package_re.match(line)
|
||||
if match:
|
||||
if package:
|
||||
self.store_result(options, package, log)
|
||||
|
||||
cpv = match.group('cpv')
|
||||
package = self.store_package(options, cpv)
|
||||
log = line
|
||||
continue
|
||||
|
||||
log += line
|
||||
|
||||
match = version_re.match(line)
|
||||
if match:
|
||||
ver = match.group('ver')
|
||||
url = match.group('url')
|
||||
self.store_version(options, package, ver, url)
|
||||
|
||||
if package:
|
||||
self.store_result(options, package, log)
|
||||
|
||||
def store_result(self, options, package, log):
|
||||
# Remove previous logs
|
||||
EuscanResult.objects.filter(package=package).delete()
|
||||
|
||||
obj = EuscanResult()
|
||||
obj.package = package
|
||||
obj.result = log
|
||||
obj.datetime = datetime.now()
|
||||
obj.save()
|
||||
|
||||
|
||||
def store_package(self, options, cpv):
|
||||
cat, pkg, ver, rev = portage.catpkgsplit(cpv)
|
||||
|
||||
obj, created = Package.objects.get_or_create(category=cat, name=pkg)
|
||||
|
||||
if created and not options['quiet']:
|
||||
sys.stdout.write('+ [p] %s/%s\n' % (cat, pkg))
|
||||
|
||||
' Set all versions dead, then set found versions alive and delete old versions '
|
||||
Version.objects.filter(package=obj, packaged=False).update(alive=False)
|
||||
|
||||
return obj
|
||||
|
||||
def store_version(self, options, package, ver, url):
|
||||
obj, created = Version.objects.get_or_create(package=package, slot='',
|
||||
revision='r0', version=ver,
|
||||
overlay='')
|
||||
|
||||
obj.alive = True
|
||||
obj.urls = url
|
||||
obj.packaged = False
|
||||
obj.save()
|
||||
|
||||
''' If it's not a new version, just update the object and continue '''
|
||||
if not created:
|
||||
return
|
||||
|
||||
if not options['quiet']:
|
||||
sys.stdout.write('+ [u] %s %s\n' % (obj, url))
|
||||
|
||||
entry = VersionLog.objects.create(package=package, action=VersionLog.VERSION_ADDED)
|
||||
entry.slot = ''
|
||||
entry.revision = 'r0'
|
||||
entry.version = ver
|
||||
entry.overlay = ''
|
||||
entry.save()
|
||||
|
||||
package.n_versions += 1
|
||||
package.save()
|
||||
|
||||
|
||||
@commit_on_success
|
||||
def purge_versions(self, options):
|
||||
' For each dead versions '
|
||||
for version in Version.objects.filter(packaged=False, alive=False):
|
||||
entry = VersionLog.objects.create(package=version.package, action=VersionLog.VERSION_REMOVED)
|
||||
entry.slot = version.slot
|
||||
entry.revision = version.revision
|
||||
entry.version = version.version
|
||||
entry.overlay = version.overlay
|
||||
entry.save()
|
||||
|
||||
version.package.n_versions -= 1
|
||||
version.package.save()
|
||||
|
||||
if not options['quiet']:
|
||||
sys.stdout.write('- [u] %s %s\n' % (version, version.urls))
|
||||
Version.objects.filter(packaged=False, alive=False).delete()
|
||||
|
185
euscanwww/djeuscan/management/commands/update-counters.py
Normal file
185
euscanwww/djeuscan/management/commands/update-counters.py
Normal file
@ -0,0 +1,185 @@
|
||||
import datetime
|
||||
|
||||
from optparse import make_option
|
||||
|
||||
from django.db.models import Count, Sum
|
||||
from django.db.transaction import commit_on_success
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
|
||||
from djeuscan.models import Package, Herd, Maintainer, Version
|
||||
from djeuscan.models import HerdLog, MaintainerLog, CategoryLog, WorldLog
|
||||
from djeuscan import charts
|
||||
|
||||
from distutils.version import StrictVersion, LooseVersion
|
||||
|
||||
def compare_versions(version1, version2):
|
||||
try:
|
||||
return cmp(StrictVersion(version1), StrictVersion(version2))
|
||||
# in case of abnormal version number, fall back to LooseVersion
|
||||
except ValueError:
|
||||
return cmp(LooseVersion(version1), LooseVersion(version2))
|
||||
|
||||
class Command(BaseCommand):
|
||||
_overlays = {}
|
||||
help = 'Update counters'
|
||||
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--quiet',
|
||||
action='store_true',
|
||||
dest='quiet',
|
||||
default=False,
|
||||
help='Be quiet'),
|
||||
make_option('--fast',
|
||||
action='store_true',
|
||||
dest='fast',
|
||||
default=False,
|
||||
help='Skip sanity checks'),
|
||||
make_option('--nolog',
|
||||
action='store_true',
|
||||
dest='nolog',
|
||||
default=False,
|
||||
help='Skip logs'),
|
||||
|
||||
)
|
||||
|
||||
@commit_on_success
|
||||
def handle(self, *args, **options):
|
||||
now = datetime.datetime.now()
|
||||
|
||||
categories = {}
|
||||
herds = {}
|
||||
maintainers = {}
|
||||
|
||||
wlog = None
|
||||
|
||||
if not options['nolog']:
|
||||
wlog = WorldLog()
|
||||
wlog.datetime = now
|
||||
|
||||
for cat in Package.objects.values('category').distinct():
|
||||
clog = CategoryLog()
|
||||
clog.datetime = now
|
||||
clog.category = cat['category']
|
||||
categories[clog.category] = clog
|
||||
|
||||
for herd in Herd.objects.all():
|
||||
hlog = HerdLog()
|
||||
hlog.datetime = now
|
||||
hlog.herd = herd
|
||||
herds[herd.id] = hlog
|
||||
|
||||
for maintainer in Maintainer.objects.all():
|
||||
mlog = MaintainerLog()
|
||||
mlog.datetime = now
|
||||
mlog.maintainer = maintainer
|
||||
maintainers[maintainer.id] = mlog
|
||||
|
||||
package_queryset = Package.objects.all()
|
||||
|
||||
n_versions = {}
|
||||
n_packaged = {}
|
||||
n_overlay = {}
|
||||
|
||||
last_versions_gentoo = {}
|
||||
last_versions_overlay = {}
|
||||
last_versions_upstream = {}
|
||||
|
||||
def add_safe(storage, key):
|
||||
if key not in storage:
|
||||
storage[key] = 1
|
||||
else:
|
||||
storage[key] += 1
|
||||
|
||||
def add_last_ver(storage, version):
|
||||
key = version['package_id']
|
||||
if key not in storage:
|
||||
storage[key] = version
|
||||
return
|
||||
if version['version'].startswith('9999'):
|
||||
return
|
||||
if compare_versions(storage[key]['version'], version['version']) < 0:
|
||||
storage[key] = version
|
||||
|
||||
if not options['fast']:
|
||||
attrs = ['id', 'version', 'overlay', 'packaged', 'package_id']
|
||||
for version in Version.objects.all().values(*attrs):
|
||||
overlay, packaged = version['overlay'], version['packaged']
|
||||
package_id = version['package_id']
|
||||
|
||||
add_safe(n_versions, package_id)
|
||||
|
||||
if not packaged:
|
||||
add_last_ver(last_versions_upstream, version)
|
||||
continue
|
||||
if overlay == 'gentoo':
|
||||
add_safe(n_packaged, package_id)
|
||||
add_last_ver(last_versions_gentoo, version)
|
||||
else:
|
||||
add_safe(n_overlay, package_id)
|
||||
add_last_ver(last_versions_overlay, version)
|
||||
|
||||
for package in package_queryset.select_related('herds', 'maintainers'):
|
||||
if not options['fast']:
|
||||
package.n_versions = n_versions.get(package.id, 0)
|
||||
package.n_packaged = n_packaged.get(package.id, 0)
|
||||
package.n_overlay = n_overlay.get(package.id, 0)
|
||||
|
||||
default = {'id' : None}
|
||||
package.last_version_gentoo_id = last_versions_gentoo.get(package.id, default)['id']
|
||||
package.last_version_overlay_id = last_versions_overlay.get(package.id, default)['id']
|
||||
package.last_version_upstream_id = last_versions_upstream.get(package.id, default)['id']
|
||||
|
||||
package.save()
|
||||
|
||||
n_packages_gentoo = int(package.n_packaged == package.n_versions)
|
||||
n_packages_overlay = int(package.n_overlay and package.n_packaged + package.n_overlay == package.n_versions)
|
||||
n_packages_outdated = int(package.n_packaged + package.n_overlay < package.n_versions)
|
||||
|
||||
def update_row(storage, key):
|
||||
storage[key].n_packages_gentoo += n_packages_gentoo
|
||||
storage[key].n_packages_overlay += n_packages_overlay
|
||||
storage[key].n_packages_outdated += n_packages_outdated
|
||||
|
||||
storage[key].n_versions_gentoo += package.n_packaged
|
||||
storage[key].n_versions_overlay += package.n_overlay
|
||||
storage[key].n_versions_upstream += package.n_versions - package.n_packaged - package.n_overlay
|
||||
def update_log(storage, qs):
|
||||
for row in qs:
|
||||
update_row(storage, row['id'])
|
||||
|
||||
if not options['nolog']:
|
||||
update_log(herds, package.herds.all().values('id'))
|
||||
update_log(maintainers, package.maintainers.all().values('id'))
|
||||
update_row(categories, package.category)
|
||||
|
||||
wlog.n_packages_gentoo += n_packages_gentoo
|
||||
wlog.n_packages_overlay += n_packages_overlay
|
||||
wlog.n_packages_outdated += n_packages_outdated
|
||||
|
||||
wlog.n_versions_gentoo += package.n_packaged
|
||||
wlog.n_versions_overlay += package.n_overlay
|
||||
wlog.n_versions_upstream += package.n_versions - package.n_packaged - package.n_overlay
|
||||
|
||||
if options['nolog']:
|
||||
return
|
||||
|
||||
for clog in categories.values():
|
||||
if not options['quiet']:
|
||||
self.stdout.write('+ [cl] %s\n' % clog)
|
||||
charts.rrd_update('category-%s' % clog.category, now, clog)
|
||||
clog.save()
|
||||
|
||||
for hlog in herds.values():
|
||||
if not options['quiet']:
|
||||
self.stdout.write('+ [hl] %s\n' % hlog)
|
||||
charts.rrd_update('herd-%d' % hlog.herd.id, now, hlog)
|
||||
hlog.save()
|
||||
|
||||
for mlog in maintainers.values():
|
||||
if not options['quiet']:
|
||||
self.stdout.write('+ [ml] %s\n' % mlog)
|
||||
charts.rrd_update('maintainer-%d' % mlog.maintainer.id, now, mlog)
|
||||
mlog.save()
|
||||
|
||||
charts.rrd_update('world', now, wlog)
|
||||
wlog.save()
|
0
euscanwww/djeuscan/management/commands/utils.py
Normal file
0
euscanwww/djeuscan/management/commands/utils.py
Normal file
283
euscanwww/djeuscan/migrations/0001_initial.py
Normal file
283
euscanwww/djeuscan/migrations/0001_initial.py
Normal file
@ -0,0 +1,283 @@
|
||||
# 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 model 'Herd'
|
||||
db.create_table('djeuscan_herd', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('herd', self.gf('django.db.models.fields.CharField')(unique=True, max_length=128)),
|
||||
('email', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['Herd'])
|
||||
|
||||
# Adding model 'Maintainer'
|
||||
db.create_table('djeuscan_maintainer', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('email', self.gf('django.db.models.fields.CharField')(unique=True, max_length=128)),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['Maintainer'])
|
||||
|
||||
# Adding model 'Package'
|
||||
db.create_table('djeuscan_package', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('category', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('homepage', self.gf('django.db.models.fields.CharField')(max_length=256, blank=True)),
|
||||
('n_versions', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
('n_packaged', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
('n_overlay', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
('last_version_gentoo', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='last_version_gentoo', null=True, to=orm['djeuscan.Version'])),
|
||||
('last_version_overlay', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='last_version_overlay', null=True, to=orm['djeuscan.Version'])),
|
||||
('last_version_upstream', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='last_version_upstream', null=True, to=orm['djeuscan.Version'])),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['Package'])
|
||||
|
||||
# Adding unique constraint on 'Package', fields ['category', 'name']
|
||||
db.create_unique('djeuscan_package', ['category', 'name'])
|
||||
|
||||
# Adding M2M table for field herds on 'Package'
|
||||
db.create_table('djeuscan_package_herds', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('package', models.ForeignKey(orm['djeuscan.package'], null=False)),
|
||||
('herd', models.ForeignKey(orm['djeuscan.herd'], null=False))
|
||||
))
|
||||
db.create_unique('djeuscan_package_herds', ['package_id', 'herd_id'])
|
||||
|
||||
# Adding M2M table for field maintainers on 'Package'
|
||||
db.create_table('djeuscan_package_maintainers', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('package', models.ForeignKey(orm['djeuscan.package'], null=False)),
|
||||
('maintainer', models.ForeignKey(orm['djeuscan.maintainer'], null=False))
|
||||
))
|
||||
db.create_unique('djeuscan_package_maintainers', ['package_id', 'maintainer_id'])
|
||||
|
||||
# Adding model 'Version'
|
||||
db.create_table('djeuscan_version', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('package', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['djeuscan.Package'])),
|
||||
('slot', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('revision', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('version', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('packaged', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
('overlay', self.gf('django.db.models.fields.CharField')(default='gentoo', max_length=128, db_index=True)),
|
||||
('urls', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('alive', self.gf('django.db.models.fields.BooleanField')(default=True, db_index=True)),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['Version'])
|
||||
|
||||
# Adding unique constraint on 'Version', fields ['package', 'slot', 'revision', 'version', 'overlay']
|
||||
db.create_unique('djeuscan_version', ['package_id', 'slot', 'revision', 'version', 'overlay'])
|
||||
|
||||
# Adding model 'VersionLog'
|
||||
db.create_table('djeuscan_versionlog', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('package', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['djeuscan.Package'])),
|
||||
('datetime', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||
('slot', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('revision', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('version', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
('packaged', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
('overlay', self.gf('django.db.models.fields.CharField')(default='gentoo', max_length=128)),
|
||||
('action', self.gf('django.db.models.fields.IntegerField')()),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['VersionLog'])
|
||||
|
||||
# Adding model 'EuscanResult'
|
||||
db.create_table('djeuscan_euscanresult', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('package', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['djeuscan.Package'])),
|
||||
('datetime', self.gf('django.db.models.fields.DateTimeField')()),
|
||||
('result', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['EuscanResult'])
|
||||
|
||||
# Adding model 'Log'
|
||||
db.create_table('djeuscan_log', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('datetime', self.gf('django.db.models.fields.DateTimeField')()),
|
||||
('n_packages_gentoo', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
('n_packages_overlay', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
('n_packages_outdated', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
('n_versions_gentoo', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
('n_versions_overlay', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
('n_versions_upstream', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['Log'])
|
||||
|
||||
# Adding model 'WorldLog'
|
||||
db.create_table('djeuscan_worldlog', (
|
||||
('log_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['djeuscan.Log'], unique=True, primary_key=True)),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['WorldLog'])
|
||||
|
||||
# Adding model 'CategoryLog'
|
||||
db.create_table('djeuscan_categorylog', (
|
||||
('log_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['djeuscan.Log'], unique=True, primary_key=True)),
|
||||
('category', self.gf('django.db.models.fields.CharField')(max_length=128)),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['CategoryLog'])
|
||||
|
||||
# Adding model 'HerdLog'
|
||||
db.create_table('djeuscan_herdlog', (
|
||||
('log_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['djeuscan.Log'], unique=True, primary_key=True)),
|
||||
('herd', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['djeuscan.Herd'])),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['HerdLog'])
|
||||
|
||||
# Adding model 'MaintainerLog'
|
||||
db.create_table('djeuscan_maintainerlog', (
|
||||
('log_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['djeuscan.Log'], unique=True, primary_key=True)),
|
||||
('maintainer', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['djeuscan.Maintainer'])),
|
||||
))
|
||||
db.send_create_signal('djeuscan', ['MaintainerLog'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Removing unique constraint on 'Version', fields ['package', 'slot', 'revision', 'version', 'overlay']
|
||||
db.delete_unique('djeuscan_version', ['package_id', 'slot', 'revision', 'version', 'overlay'])
|
||||
|
||||
# Removing unique constraint on 'Package', fields ['category', 'name']
|
||||
db.delete_unique('djeuscan_package', ['category', 'name'])
|
||||
|
||||
# Deleting model 'Herd'
|
||||
db.delete_table('djeuscan_herd')
|
||||
|
||||
# Deleting model 'Maintainer'
|
||||
db.delete_table('djeuscan_maintainer')
|
||||
|
||||
# Deleting model 'Package'
|
||||
db.delete_table('djeuscan_package')
|
||||
|
||||
# Removing M2M table for field herds on 'Package'
|
||||
db.delete_table('djeuscan_package_herds')
|
||||
|
||||
# Removing M2M table for field maintainers on 'Package'
|
||||
db.delete_table('djeuscan_package_maintainers')
|
||||
|
||||
# Deleting model 'Version'
|
||||
db.delete_table('djeuscan_version')
|
||||
|
||||
# Deleting model 'VersionLog'
|
||||
db.delete_table('djeuscan_versionlog')
|
||||
|
||||
# Deleting model 'EuscanResult'
|
||||
db.delete_table('djeuscan_euscanresult')
|
||||
|
||||
# Deleting model 'Log'
|
||||
db.delete_table('djeuscan_log')
|
||||
|
||||
# Deleting model 'WorldLog'
|
||||
db.delete_table('djeuscan_worldlog')
|
||||
|
||||
# Deleting model 'CategoryLog'
|
||||
db.delete_table('djeuscan_categorylog')
|
||||
|
||||
# Deleting model 'HerdLog'
|
||||
db.delete_table('djeuscan_herdlog')
|
||||
|
||||
# Deleting model 'MaintainerLog'
|
||||
db.delete_table('djeuscan_maintainerlog')
|
||||
|
||||
|
||||
models = {
|
||||
'djeuscan.categorylog': {
|
||||
'Meta': {'object_name': 'CategoryLog', '_ormbases': ['djeuscan.Log']},
|
||||
'category': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'log_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['djeuscan.Log']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'djeuscan.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['djeuscan.Package']"}),
|
||||
'result': ('django.db.models.fields.TextField', [], {'blank': 'True'})
|
||||
},
|
||||
'djeuscan.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'})
|
||||
},
|
||||
'djeuscan.herdlog': {
|
||||
'Meta': {'object_name': 'HerdLog', '_ormbases': ['djeuscan.Log']},
|
||||
'herd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djeuscan.Herd']"}),
|
||||
'log_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['djeuscan.Log']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'djeuscan.log': {
|
||||
'Meta': {'object_name': 'Log'},
|
||||
'datetime': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'n_packages_gentoo': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_packages_outdated': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_packages_overlay': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_versions_gentoo': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_versions_overlay': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_versions_upstream': ('django.db.models.fields.IntegerField', [], {'default': '0'})
|
||||
},
|
||||
'djeuscan.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'})
|
||||
},
|
||||
'djeuscan.maintainerlog': {
|
||||
'Meta': {'object_name': 'MaintainerLog', '_ormbases': ['djeuscan.Log']},
|
||||
'log_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['djeuscan.Log']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djeuscan.Maintainer']"})
|
||||
},
|
||||
'djeuscan.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['djeuscan.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'}),
|
||||
'last_version_gentoo': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_version_gentoo'", 'null': 'True', 'to': "orm['djeuscan.Version']"}),
|
||||
'last_version_overlay': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_version_overlay'", 'null': 'True', 'to': "orm['djeuscan.Version']"}),
|
||||
'last_version_upstream': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_version_upstream'", 'null': 'True', 'to': "orm['djeuscan.Version']"}),
|
||||
'maintainers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['djeuscan.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'})
|
||||
},
|
||||
'djeuscan.version': {
|
||||
'Meta': {'unique_together': "(['package', 'slot', 'revision', 'version', 'overlay'],)", 'object_name': 'Version'},
|
||||
'alive': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'overlay': ('django.db.models.fields.CharField', [], {'default': "'gentoo'", 'max_length': '128', 'db_index': 'True'}),
|
||||
'package': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djeuscan.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'})
|
||||
},
|
||||
'djeuscan.versionlog': {
|
||||
'Meta': {'object_name': 'VersionLog'},
|
||||
'action': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'datetime': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'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['djeuscan.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'}),
|
||||
'version': ('django.db.models.fields.CharField', [], {'max_length': '128'})
|
||||
},
|
||||
'djeuscan.worldlog': {
|
||||
'Meta': {'object_name': 'WorldLog', '_ormbases': ['djeuscan.Log']},
|
||||
'log_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['djeuscan.Log']", 'unique': 'True', 'primary_key': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['djeuscan']
|
@ -0,0 +1,113 @@
|
||||
# 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):
|
||||
|
||||
# Changing field 'Package.homepage'
|
||||
db.alter_column('djeuscan_package', 'homepage', self.gf('django.db.models.fields.TextField')())
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Changing field 'Package.homepage'
|
||||
db.alter_column('djeuscan_package', 'homepage', self.gf('django.db.models.fields.CharField')(max_length=256))
|
||||
|
||||
|
||||
models = {
|
||||
'djeuscan.categorylog': {
|
||||
'Meta': {'object_name': 'CategoryLog', '_ormbases': ['djeuscan.Log']},
|
||||
'category': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'log_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['djeuscan.Log']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'djeuscan.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['djeuscan.Package']"}),
|
||||
'result': ('django.db.models.fields.TextField', [], {'blank': 'True'})
|
||||
},
|
||||
'djeuscan.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'})
|
||||
},
|
||||
'djeuscan.herdlog': {
|
||||
'Meta': {'object_name': 'HerdLog', '_ormbases': ['djeuscan.Log']},
|
||||
'herd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djeuscan.Herd']"}),
|
||||
'log_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['djeuscan.Log']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'djeuscan.log': {
|
||||
'Meta': {'object_name': 'Log'},
|
||||
'datetime': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'n_packages_gentoo': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_packages_outdated': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_packages_overlay': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_versions_gentoo': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_versions_overlay': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'n_versions_upstream': ('django.db.models.fields.IntegerField', [], {'default': '0'})
|
||||
},
|
||||
'djeuscan.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'})
|
||||
},
|
||||
'djeuscan.maintainerlog': {
|
||||
'Meta': {'object_name': 'MaintainerLog', '_ormbases': ['djeuscan.Log']},
|
||||
'log_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['djeuscan.Log']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djeuscan.Maintainer']"})
|
||||
},
|
||||
'djeuscan.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['djeuscan.Herd']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'homepage': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_version_gentoo': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_version_gentoo'", 'null': 'True', 'to': "orm['djeuscan.Version']"}),
|
||||
'last_version_overlay': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_version_overlay'", 'null': 'True', 'to': "orm['djeuscan.Version']"}),
|
||||
'last_version_upstream': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_version_upstream'", 'null': 'True', 'to': "orm['djeuscan.Version']"}),
|
||||
'maintainers': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['djeuscan.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'})
|
||||
},
|
||||
'djeuscan.version': {
|
||||
'Meta': {'unique_together': "(['package', 'slot', 'revision', 'version', 'overlay'],)", 'object_name': 'Version'},
|
||||
'alive': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'overlay': ('django.db.models.fields.CharField', [], {'default': "'gentoo'", 'max_length': '128', 'db_index': 'True'}),
|
||||
'package': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djeuscan.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'})
|
||||
},
|
||||
'djeuscan.versionlog': {
|
||||
'Meta': {'object_name': 'VersionLog'},
|
||||
'action': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'datetime': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'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['djeuscan.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'}),
|
||||
'version': ('django.db.models.fields.CharField', [], {'max_length': '128'})
|
||||
},
|
||||
'djeuscan.worldlog': {
|
||||
'Meta': {'object_name': 'WorldLog', '_ormbases': ['djeuscan.Log']},
|
||||
'log_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['djeuscan.Log']", 'unique': 'True', 'primary_key': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['djeuscan']
|
0
euscanwww/djeuscan/migrations/__init__.py
Normal file
0
euscanwww/djeuscan/migrations/__init__.py
Normal file
144
euscanwww/djeuscan/models.py
Normal file
144
euscanwww/djeuscan/models.py
Normal file
@ -0,0 +1,144 @@
|
||||
from django.db import models
|
||||
|
||||
class Herd(models.Model):
|
||||
herd = models.CharField(max_length=128, unique=True)
|
||||
email = models.CharField(max_length=128, blank=True, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
if self.email:
|
||||
return '%s <%s>' % (self.herd, self.email)
|
||||
return self.herd
|
||||
|
||||
class Maintainer(models.Model):
|
||||
name = models.CharField(max_length=128)
|
||||
email = models.CharField(max_length=128, unique=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return '%s <%s>' % (self.name, self.email)
|
||||
|
||||
class Package(models.Model):
|
||||
category = models.CharField(max_length=128)
|
||||
name = models.CharField(max_length=128)
|
||||
description = models.TextField(blank=True)
|
||||
homepage = models.TextField(blank=True)
|
||||
herds = models.ManyToManyField(Herd, blank=True)
|
||||
maintainers = models.ManyToManyField(Maintainer, blank=True)
|
||||
|
||||
' 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)
|
||||
|
||||
' And we also pre-compute last versions '
|
||||
last_version_gentoo = models.ForeignKey('Version', blank=True, null=True,
|
||||
related_name="last_version_gentoo",
|
||||
on_delete=models.SET_NULL)
|
||||
last_version_overlay = models.ForeignKey('Version', blank=True, null=True,
|
||||
related_name="last_version_overlay",
|
||||
on_delete=models.SET_NULL)
|
||||
last_version_upstream = models.ForeignKey('Version', blank=True, null=True,
|
||||
related_name="last_version_upstream",
|
||||
on_delete=models.SET_NULL)
|
||||
|
||||
def __unicode__(self):
|
||||
return '%s/%s' % (self.category, self.name)
|
||||
|
||||
class Meta:
|
||||
unique_together = ['category', 'name']
|
||||
|
||||
class Version(models.Model):
|
||||
package = models.ForeignKey(Package)
|
||||
slot = models.CharField(max_length=128)
|
||||
revision = models.CharField(max_length=128)
|
||||
version = models.CharField(max_length=128)
|
||||
packaged = models.BooleanField()
|
||||
overlay = models.CharField(max_length=128, default='gentoo', db_index=True)
|
||||
urls = models.TextField(blank=True)
|
||||
alive = models.BooleanField(default=True, db_index=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return '%s/%s-%s-%s:%s [%s]' % (self.package.category, self.package.name,
|
||||
self.version, self.revision, self.slot,
|
||||
self.overlay)
|
||||
|
||||
class Meta:
|
||||
unique_together = ['package', 'slot', 'revision', 'version', 'overlay']
|
||||
|
||||
class VersionLog(models.Model):
|
||||
VERSION_ADDED = 1
|
||||
VERSION_REMOVED = 2
|
||||
VERSION_ACTIONS = (
|
||||
(VERSION_ADDED, 'Added'),
|
||||
(VERSION_REMOVED, 'Removed')
|
||||
)
|
||||
|
||||
package = models.ForeignKey(Package)
|
||||
datetime = models.DateTimeField(auto_now_add=True)
|
||||
slot = models.CharField(max_length=128)
|
||||
revision = models.CharField(max_length=128)
|
||||
version = models.CharField(max_length=128)
|
||||
packaged = models.BooleanField()
|
||||
overlay = models.CharField(max_length=128, default='gentoo')
|
||||
action = models.IntegerField(choices=VERSION_ACTIONS)
|
||||
|
||||
def tag(self):
|
||||
return '%s-%s:%s-[%s]' % (self.version, self.revision, self.slot,
|
||||
self.overlay)
|
||||
|
||||
def __unicode__(self):
|
||||
txt = '+ ' if self.action == self.VERSION_ADDED else '- '
|
||||
txt += '%s/%s-%s-%s:%s [%s]' % (self.package.category, self.package.name,
|
||||
self.version, self.revision, self.slot,
|
||||
self.overlay if self.overlay else '<upstream>')
|
||||
return txt
|
||||
|
||||
class EuscanResult(models.Model):
|
||||
package = models.ForeignKey(Package)
|
||||
datetime = models.DateTimeField()
|
||||
result = models.TextField(blank=True)
|
||||
|
||||
# Keep data for charts
|
||||
class Log(models.Model):
|
||||
datetime = models.DateTimeField()
|
||||
|
||||
' Packages up to date in the main portage tree '
|
||||
n_packages_gentoo = models.IntegerField(default=0)
|
||||
' Packages up to date in an overlay '
|
||||
n_packages_overlay = models.IntegerField(default=0)
|
||||
' Packages outdated '
|
||||
n_packages_outdated = models.IntegerField(default=0)
|
||||
|
||||
' Versions in the main portage tree '
|
||||
n_versions_gentoo = models.IntegerField(default=0)
|
||||
' Versions in overlays '
|
||||
n_versions_overlay = models.IntegerField(default=0)
|
||||
' Upstream versions, not in the main tree or overlays '
|
||||
n_versions_upstream = models.IntegerField(default=0)
|
||||
|
||||
def __unicode__(self):
|
||||
return u'[%d:%d:%d] [%d:%d:%d]' % \
|
||||
(self.n_packages_gentoo, self.n_packages_overlay, self.n_packages_outdated, \
|
||||
self.n_versions_gentoo, self.n_versions_overlay, self.n_versions_upstream)
|
||||
|
||||
class WorldLog(Log):
|
||||
def __unicode__(self):
|
||||
return u'world ' + Log.__unicode__(self)
|
||||
|
||||
class CategoryLog(Log):
|
||||
category = models.CharField(max_length=128)
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s %s' % (self.category, Log.__unicode__(self))
|
||||
|
||||
class HerdLog(Log):
|
||||
herd = models.ForeignKey(Herd)
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s %s' % (self.herd, Log.__unicode__(self))
|
||||
|
||||
class MaintainerLog(Log):
|
||||
maintainer = models.ForeignKey(Maintainer)
|
||||
|
||||
def __unicode__(self):
|
||||
return u'%s %s' % (self.maintainer, Log.__unicode__(self))
|
||||
|
0
euscanwww/djeuscan/templatetags/__init__.py
Normal file
0
euscanwww/djeuscan/templatetags/__init__.py
Normal file
8
euscanwww/djeuscan/templatetags/div.py
Normal file
8
euscanwww/djeuscan/templatetags/div.py
Normal file
@ -0,0 +1,8 @@
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
def div(value, arg=None):
|
||||
return float(value)/float(arg)
|
||||
|
||||
register.filter('div', div)
|
29
euscanwww/djeuscan/templatetags/math_.py
Normal file
29
euscanwww/djeuscan/templatetags/math_.py
Normal file
@ -0,0 +1,29 @@
|
||||
from django.template import Node, Library
|
||||
import math
|
||||
|
||||
register = Library()
|
||||
|
||||
# taken from http://lybniz2.sourceforge.net/safeeval.html
|
||||
# make a list of safe functions
|
||||
math_safe_list = ['acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
|
||||
|
||||
# use the list to filter the local namespace
|
||||
math_safe_dict = dict([(k, getattr(math, k)) for k in math_safe_list])
|
||||
|
||||
# add any needed builtins back in.
|
||||
math_safe_dict['abs'] = abs
|
||||
|
||||
@register.filter('math')
|
||||
def math_(lopr, expr):
|
||||
"""Evals a math expression and returns it's value.
|
||||
|
||||
"$1" is a placeholder. Insert "$1" in the expression where the value is to be used. All math functions such as abs, sin, cos, floor are supported.
|
||||
Example,
|
||||
a. You will be redirected in {{ seconds|math:"$1 / 60.0" }} minutes
|
||||
b. Square of {{ x }} is {{ x|math:"$1 * $1" }}
|
||||
c. Square root of {{ x }} is {{ x|math:"sqrt($1)" }}
|
||||
d. Given x = {{ x }}, (2 + x) * 6 = {{ x|math:"(2 + $1) * 6" }}
|
||||
"""
|
||||
if lopr:
|
||||
return eval(expr.replace('$1', str(lopr)), {"__builtins__": None}, math_safe_dict)
|
||||
return ''
|
8
euscanwww/djeuscan/templatetags/mul.py
Normal file
8
euscanwww/djeuscan/templatetags/mul.py
Normal file
@ -0,0 +1,8 @@
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
def mul(value, arg=None):
|
||||
return value*arg
|
||||
|
||||
register.filter('mul', mul)
|
18
euscanwww/djeuscan/templatetags/packages.py
Normal file
18
euscanwww/djeuscan/templatetags/packages.py
Normal file
@ -0,0 +1,18 @@
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.inclusion_tag('euscan/_packages.html', takes_context=True)
|
||||
def packages(context, packages):
|
||||
context['packages'] = packages
|
||||
return context
|
||||
|
||||
@register.inclusion_tag('euscan/_package_cols.html', takes_context=True)
|
||||
def package_cols(context, infos):
|
||||
context['infos'] = infos
|
||||
return context
|
||||
|
||||
@register.inclusion_tag('euscan/_package_bar.html', takes_context=True)
|
||||
def package_bar(context, infos):
|
||||
context['infos'] = infos
|
||||
return context
|
8
euscanwww/djeuscan/templatetags/sub.py
Normal file
8
euscanwww/djeuscan/templatetags/sub.py
Normal file
@ -0,0 +1,8 @@
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
def sub(value, arg=None):
|
||||
return value-arg
|
||||
|
||||
register.filter('sub', sub)
|
23
euscanwww/djeuscan/templatetags/timedelta.py
Normal file
23
euscanwww/djeuscan/templatetags/timedelta.py
Normal file
@ -0,0 +1,23 @@
|
||||
from django import template
|
||||
from django.utils.timesince import timesince
|
||||
from django.conf import settings
|
||||
from django.utils.timezone import make_aware, get_default_timezone
|
||||
from datetime import datetime
|
||||
|
||||
register = template.Library()
|
||||
|
||||
def timedelta(value, arg=None):
|
||||
if not value:
|
||||
return ''
|
||||
if arg:
|
||||
cmp = arg
|
||||
else:
|
||||
cmp = datetime.now()
|
||||
if settings.USE_TZ:
|
||||
cmp = make_aware(cmp, get_default_timezone())
|
||||
if value > cmp:
|
||||
return "in %s" % timesince(cmp,value)
|
||||
else:
|
||||
return "%s ago" % timesince(value,cmp)
|
||||
|
||||
register.filter('timedelta',timedelta)
|
23
euscanwww/djeuscan/tests.py
Normal file
23
euscanwww/djeuscan/tests.py
Normal file
@ -0,0 +1,23 @@
|
||||
"""
|
||||
This file demonstrates two different styles of tests (one doctest and one
|
||||
unittest). These will both pass when you run "manage.py test".
|
||||
|
||||
Replace these with more appropriate tests for your application.
|
||||
"""
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
"""
|
||||
self.failUnlessEqual(1 + 1, 2)
|
||||
|
||||
__test__ = {"doctest": """
|
||||
Another way to test that 1 + 1 is equal to 2.
|
||||
|
||||
>>> 1 + 1 == 2
|
||||
True
|
||||
"""}
|
||||
|
54
euscanwww/djeuscan/urls.py
Normal file
54
euscanwww/djeuscan/urls.py
Normal file
@ -0,0 +1,54 @@
|
||||
from django.conf.urls.defaults import *
|
||||
from feeds import *
|
||||
|
||||
package_patterns = patterns('djeuscan.views',
|
||||
url(r'^(?P<category>[\w+][\w+.-]*)/(?P<package>[\w+][\w+.-]*)/feed/$', PackageFeed(), name='package_feed'),
|
||||
(r'^(?P<category>[\w+][\w+.-]*)/(?P<package>[\w+][\w+.-]*)/$', 'package'),
|
||||
)
|
||||
|
||||
categories_patterns = patterns('djeuscan.views',
|
||||
(r'^(?P<category>[\w+][\w+.-]*)/(view/)?$', 'category'),
|
||||
url(r'^(?P<category>[\w+][\w+.-]*)/feed/$', CategoryFeed(), name='category_feed'),
|
||||
(r'^(?P<category>[\w+][\w+.-]*)/charts/(?P<chart>[\w\-]+).png$', 'chart_category'),
|
||||
(r'^$', 'categories'),
|
||||
)
|
||||
|
||||
herds_patterns = patterns('djeuscan.views',
|
||||
(r'^(?P<herd>[\@\{\}\w+.-]*)/(view/)?$', 'herd'),
|
||||
url(r'^(?P<herd>[\@\{\}\w+.-]*)/feed/$', HerdFeed(), name='herd_feed'),
|
||||
(r'^(?P<herd>[\@\{\}\w+.-]*)/charts/(?P<chart>[\w\-]+).png$', 'chart_herd'),
|
||||
(r'^$', 'herds'),
|
||||
)
|
||||
|
||||
maintainers_patterns = patterns('djeuscan.views',
|
||||
(r'^(?P<maintainer_id>\d+)/(view/)?$', 'maintainer'),
|
||||
url(r'^(?P<maintainer_id>\d+)/feed/$', MaintainerFeed(), name='maintainer_feed'),
|
||||
(r'^(?P<maintainer_id>\d+)/charts/(?P<chart>[\w\-]+).png$', 'chart_maintainer'),
|
||||
(r'^$', 'maintainers'),
|
||||
)
|
||||
|
||||
overlays_patterns = patterns('djeuscan.views',
|
||||
(r'^(?P<overlay>[\w+][\w+.-]*)/(view/)?$', 'overlay'),
|
||||
(r'^$', 'overlays'),
|
||||
)
|
||||
|
||||
urlpatterns = patterns('djeuscan.views',
|
||||
# Global stuff
|
||||
(r'^api/', include('djeuscan.api.urls')),
|
||||
|
||||
(r'^$', 'index'),
|
||||
url(r'^feed/$', GlobalFeed(), name='global_feed'),
|
||||
(r'^about/$', 'about'),
|
||||
(r'^about/api$', 'api'),
|
||||
(r'^statistics/$', 'statistics'),
|
||||
(r'^statistics/charts/(?P<chart>[\w\-]+).png$', 'chart'),
|
||||
(r'^world/$', 'world'),
|
||||
(r'^world/scan/$', 'world_scan'),
|
||||
|
||||
# Real data
|
||||
(r'^categories/', include(categories_patterns)),
|
||||
(r'^herds/', include(herds_patterns)),
|
||||
(r'^maintainers/', include(maintainers_patterns)),
|
||||
(r'^overlays/', include(overlays_patterns)),
|
||||
(r'^package/', include(package_patterns)),
|
||||
)
|
212
euscanwww/djeuscan/views.py
Normal file
212
euscanwww/djeuscan/views.py
Normal file
@ -0,0 +1,212 @@
|
||||
from annoying.decorators import render_to
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.db.models import Sum, Max
|
||||
|
||||
from models import Version, Package, Herd, Maintainer, EuscanResult, VersionLog
|
||||
from forms import WorldForm, PackagesForm
|
||||
|
||||
import charts
|
||||
|
||||
""" Views """
|
||||
|
||||
@render_to('euscan/index.html')
|
||||
def index(request):
|
||||
ctx = {}
|
||||
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()
|
||||
|
||||
try:
|
||||
ctx['last_scan'] = EuscanResult.objects.get(id=EuscanResult.objects.aggregate(Max('id'))['id__max']).datetime
|
||||
except EuscanResult.DoesNotExist:
|
||||
ctx['last_scan'] = None
|
||||
|
||||
return ctx
|
||||
|
||||
@render_to('euscan/logs.html')
|
||||
def logs(request):
|
||||
return {}
|
||||
|
||||
@render_to('euscan/categories.html')
|
||||
def categories(request):
|
||||
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')
|
||||
def category(request, category):
|
||||
packages = Package.objects.filter(category=category)
|
||||
packages = packages.select_related('last_version_gentoo', 'last_version_overlay', 'last_version_upstream')
|
||||
print dir(packages[0])
|
||||
if not packages:
|
||||
raise Http404
|
||||
return { 'category' : category, 'packages' : packages }
|
||||
|
||||
@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)
|
||||
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')
|
||||
def herd(request, herd):
|
||||
herd = get_object_or_404(Herd, herd=herd)
|
||||
packages = Package.objects.filter(herds__id=herd.id)
|
||||
packages = packages.select_related('last_version_gentoo', 'last_version_overlay', 'last_version_upstream')
|
||||
return { 'herd' : herd, 'packages' : packages }
|
||||
|
||||
@render_to('euscan/maintainers.html')
|
||||
def maintainers(request):
|
||||
maintainers = Package.objects.filter(maintainers__isnull=False)
|
||||
maintainers = maintainers.values('maintainers__id', 'maintainers__name', 'maintainers__email')
|
||||
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')
|
||||
def maintainer(request, maintainer_id):
|
||||
maintainer = get_object_or_404(Maintainer, id=maintainer_id)
|
||||
packages = Package.objects.filter(maintainers__id=maintainer.id)
|
||||
packages = packages.select_related('last_version_gentoo', 'last_version_overlay', 'last_version_upstream')
|
||||
return { 'maintainer' : maintainer, 'packages' : packages }
|
||||
|
||||
@render_to('euscan/overlays.html')
|
||||
def overlays(request):
|
||||
overlays = Package.objects.values('version__overlay')
|
||||
overlays = overlays.exclude(version__overlay='')
|
||||
overlays = overlays.distinct()
|
||||
return { 'overlays' : overlays }
|
||||
|
||||
@render_to('euscan/overlay.html')
|
||||
def overlay(request, overlay):
|
||||
packages = Package.objects.values('id', 'name', 'category',
|
||||
'n_versions', 'n_packaged',
|
||||
'n_overlay')
|
||||
packages = packages.filter(version__overlay=overlay).distinct()
|
||||
if not packages:
|
||||
raise Http404
|
||||
return { 'overlay' : overlay, 'packages' : packages }
|
||||
|
||||
@render_to('euscan/package.html')
|
||||
def package(request, category, package):
|
||||
|
||||
def version_key(version):
|
||||
from distutils.version import StrictVersion, LooseVersion
|
||||
|
||||
version = version.version
|
||||
try:
|
||||
return StrictVersion(version)
|
||||
# in case of abnormal version number, fall back to LooseVersion
|
||||
except ValueError:
|
||||
return LooseVersion(version)
|
||||
|
||||
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)
|
||||
|
||||
packaged = sorted(packaged, key=version_key)
|
||||
upstream = sorted(upstream, key=version_key)
|
||||
|
||||
log = EuscanResult.objects.filter(package=package).order_by('-datetime')[:1]
|
||||
log = log[0] if log else None
|
||||
vlog = VersionLog.objects.filter(package=package).order_by('-id')
|
||||
return { 'package' : package, 'packaged' : packaged,
|
||||
'upstream' : upstream, 'log' : log, 'vlog' : vlog }
|
||||
|
||||
@render_to('euscan/world.html')
|
||||
def world(request):
|
||||
world_form = WorldForm()
|
||||
packages_form = PackagesForm()
|
||||
|
||||
return { 'world_form' : world_form,
|
||||
'packages_form' : packages_form }
|
||||
|
||||
@render_to('euscan/world_scan.html')
|
||||
def world_scan(request):
|
||||
packages = []
|
||||
|
||||
if 'world' in request.FILES:
|
||||
data = request.FILES['world'].read()
|
||||
elif 'packages' in request.POST:
|
||||
data = request.POST['packages']
|
||||
else:
|
||||
data = ""
|
||||
|
||||
data = data.replace("\r", "")
|
||||
|
||||
for pkg in data.split('\n'):
|
||||
try:
|
||||
if '/' in pkg:
|
||||
cat, pkg = pkg.split('/')
|
||||
packages.extend(Package.objects.filter(category=cat, name=pkg))
|
||||
else:
|
||||
packages.extend(Package.objects.filter(name=pkg))
|
||||
except:
|
||||
pass
|
||||
|
||||
return { 'packages' : packages }
|
||||
|
||||
|
||||
@render_to("euscan/about.html")
|
||||
def about(request):
|
||||
return {}
|
||||
|
||||
@render_to("euscan/api.html")
|
||||
def api(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'])
|
||||
|
||||
for kw in ('-small', '-weekly', '-monthly', '-yearly'):
|
||||
if chart.endswith(kw):
|
||||
if kw in ('-weekly', '-monthly', '-yearly'):
|
||||
kwargs['period'] = kw
|
||||
kwargs[kw] = True
|
||||
chart = chart[:-len(kw)]
|
||||
|
||||
if chart == 'pie-packages':
|
||||
path = charts.pie_packages(**kwargs)
|
||||
elif chart == 'pie-versions':
|
||||
path = charts.pie_versions(**kwargs)
|
||||
elif chart == 'packages':
|
||||
path = charts.packages(**kwargs)
|
||||
elif chart == 'versions':
|
||||
path = charts.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)
|
Reference in New Issue
Block a user