Move package utility functions

We now have a few of them, so move them to their own file like we do in the
other applications.

Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Dan McGee 2010-08-28 10:53:27 -05:00
parent 4c3100ab90
commit 2750b94345
3 changed files with 111 additions and 102 deletions

103
packages/utils.py Normal file
View File

@ -0,0 +1,103 @@
from django.db import connection
from django.db.models import Count, Max
from operator import itemgetter
from main.models import Package
from main.utils import cache_function
from .models import PackageGroup
@cache_function(300)
def get_group_info():
raw_groups = PackageGroup.objects.values_list(
'name', 'pkg__arch__name').order_by('name').annotate(
cnt=Count('pkg'), last_update=Max('pkg__last_update'))
# now for post_processing. we need to seperate things out and add
# the count in for 'any' to all of the other architectures.
group_mapping = {}
for grp in raw_groups:
arch_groups = group_mapping.setdefault(grp[1], {})
arch_groups[grp[0]] = {'name': grp[0], 'arch': grp[1],
'count': grp[2], 'last_update': grp[3]}
# we want to promote the count of 'any' packages in groups to the
# other architectures, and also add any 'any'-only groups
if 'any' in group_mapping:
any_groups = group_mapping['any']
del group_mapping['any']
for arch, arch_groups in group_mapping.iteritems():
for grp in any_groups.itervalues():
if grp['name'] in arch_groups:
found = arch_groups[grp['name']]
found['count'] += grp['count']
if grp['last_update'] > found['last_update']:
found['last_update'] = grp['last_update']
else:
new_g = grp.copy()
# override the arch to not be 'any'
new_g['arch'] = arch
arch_groups[grp['name']] = new_g
# now transform it back into a sorted list
groups = []
for val in group_mapping.itervalues():
groups.extend(val.itervalues())
return sorted(groups, key=itemgetter('name', 'arch'))
@cache_function(300)
def get_differences_info(arch_a, arch_b):
# This is a monster. Join packages against itself, looking for packages in
# our non-'any' architectures only, and not having a corresponding package
# entry in the other table (or having one with a different pkgver). We will
# then go and fetch all of these packages from the database and display
# them later using normal ORM models.
sql = """
SELECT p.id, q.id
FROM packages p
LEFT JOIN packages q
ON (
p.pkgname = q.pkgname
AND p.repo_id = q.repo_id
AND p.arch_id != q.arch_id
AND p.id != q.id
)
WHERE p.arch_id IN (%s, %s)
AND (
q.id IS NULL
OR
p.pkgver != q.pkgver
OR
p.pkgrel != q.pkgrel
)
"""
cursor = connection.cursor()
cursor.execute(sql, [arch_a.id, arch_b.id])
results = cursor.fetchall()
to_fetch = []
for row in results:
# column A will always have a value, column B might be NULL
to_fetch.append(row[0])
# fetch all of the necessary packages
pkgs = Package.objects.in_bulk(to_fetch)
# now build a list of tuples containing differences
differences = []
for row in results:
pkg_a = pkgs.get(row[0])
pkg_b = pkgs.get(row[1])
# We want arch_a to always appear first
# pkg_a should never be None
if pkg_a.arch == arch_a:
item = (pkg_a.pkgname, pkg_a.repo, pkg_a, pkg_b)
else:
# pkg_b can be None in this case, so be careful
name = pkg_a.pkgname if pkg_a else pkg_b.pkgname
repo = pkg_a.repo if pkg_a else pkg_b.repo
item = (name, repo, pkg_b, pkg_a)
if item not in differences:
differences.append(item)
# now sort our list by repository, package name
differences.sort(key=lambda a: (a[1].name, a[0]))
return differences
# vim: set ts=4 sw=4 et:

View File

@ -11,17 +11,17 @@
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
from django.views.decorators.vary import vary_on_headers from django.views.decorators.vary import vary_on_headers
from django.views.generic import list_detail from django.views.generic import list_detail
from django.db.models import Count, Max, Q from django.db.models import Q
from datetime import datetime from datetime import datetime
from operator import itemgetter
import string import string
from main.models import Package, PackageFile from main.models import Package, PackageFile
from main.models import Arch, Repo, Signoff from main.models import Arch, Repo, Signoff
from main.models import MirrorUrl from main.models import MirrorUrl
from main.utils import cache_function, make_choice from main.utils import make_choice
from packages.models import PackageGroup, PackageRelation from .models import PackageGroup, PackageRelation
from .utils import get_group_info, get_differences_info
def opensearch(request): def opensearch(request):
if request.is_secure(): if request.is_secure():
@ -85,45 +85,8 @@ def details(request, name='', repo='', arch=''):
return HttpResponseRedirect("/packages/?arch=%s&repo=%s&q=%s" % ( return HttpResponseRedirect("/packages/?arch=%s&repo=%s&q=%s" % (
arch.lower(), repo.title(), name)) arch.lower(), repo.title(), name))
@cache_function(300)
def get_group_information():
raw_groups = PackageGroup.objects.values_list(
'name', 'pkg__arch__name').order_by('name').annotate(
cnt=Count('pkg'), last_update=Max('pkg__last_update'))
# now for post_processing. we need to seperate things out and add
# the count in for 'any' to all of the other architectures.
group_mapping = {}
for g in raw_groups:
arch_groups = group_mapping.setdefault(g[1], {})
arch_groups[g[0]] = {'name': g[0], 'arch': g[1],
'count': g[2], 'last_update': g[3]}
# we want to promote the count of 'any' packages in groups to the
# other architectures, and also add any 'any'-only groups
if 'any' in group_mapping:
any_groups = group_mapping['any']
del group_mapping['any']
for arch, arch_groups in group_mapping.iteritems():
for g in any_groups.itervalues():
if g['name'] in arch_groups:
found = arch_groups[g['name']]
found['count'] += g['count']
if g['last_update'] > found['last_update']:
found['last_update'] = g['last_update']
else:
new_g = g.copy()
# override the arch to not be 'any'
new_g['arch'] = arch
arch_groups[g['name']] = new_g
# now transform it back into a sorted list
groups = []
for v in group_mapping.itervalues():
groups.extend(v.itervalues())
return sorted(groups, key=itemgetter('name', 'arch'))
def groups(request): def groups(request):
groups = get_group_information() groups = get_group_info()
return render_to_response('packages/groups.html', return render_to_response('packages/groups.html',
RequestContext(request, {'groups': groups})) RequestContext(request, {'groups': groups}))
@ -400,68 +363,11 @@ def download(request, name='', repo='', arch=''):
url = string.Template('${host}${repo}/os/${arch}/${file}').substitute(details) url = string.Template('${host}${repo}/os/${arch}/${file}').substitute(details)
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
@cache_function(300)
def get_differences_information(arch_a, arch_b):
from django.db import connection
# This is a monster. Join packages against itself, looking for packages in
# our non-'any' architectures only, and not having a corresponding package
# entry in the other table (or having one with a different pkgver). We will
# then go and fetch all of these packages from the database and display
# them later using normal ORM models.
sql = """
SELECT p.id, q.id
FROM packages p
LEFT JOIN packages q
ON (
p.pkgname = q.pkgname
AND p.repo_id = q.repo_id
AND p.arch_id != q.arch_id
AND p.id != q.id
)
WHERE p.arch_id IN (%s, %s)
AND (
q.id IS NULL
OR
p.pkgver != q.pkgver
OR
p.pkgrel != q.pkgrel
)
"""
cursor = connection.cursor()
cursor.execute(sql, [arch_a.id, arch_b.id])
results = cursor.fetchall()
to_fetch = []
for row in results:
# column A will always have a value, column B might be NULL
to_fetch.append(row[0])
# fetch all of the necessary packages
pkgs = Package.objects.in_bulk(to_fetch)
# now build a list of tuples containing differences
differences = []
for row in results:
pkg_a = pkgs.get(row[0])
pkg_b = pkgs.get(row[1])
# We want arch_a to always appear first
# pkg_a should never be None
if pkg_a.arch == arch_a:
item = (pkg_a.pkgname, pkg_a.repo, pkg_a, pkg_b)
else:
# pkg_b can be None in this case, so be careful
name = pkg_a.pkgname if pkg_a else pkg_b.pkgname
repo = pkg_a.repo if pkg_a else pkg_b.repo
item = (name, repo, pkg_b, pkg_a)
if item not in differences:
differences.append(item)
# now sort our list by repository, package name
differences.sort(key=lambda a: (a[1].name, a[0]))
return differences
def arch_differences(request): def arch_differences(request):
# TODO: we have some hardcoded magic here with respect to the arches. # TODO: we have some hardcoded magic here with respect to the arches.
arch_a = Arch.objects.get(name='i686') arch_a = Arch.objects.get(name='i686')
arch_b = Arch.objects.get(name='x86_64') arch_b = Arch.objects.get(name='x86_64')
differences = get_differences_information(arch_a, arch_b) differences = get_differences_info(arch_a, arch_b)
context = { context = {
'arch_a': arch_a, 'arch_a': arch_a,
'arch_b': arch_b, 'arch_b': arch_b,

View File

@ -1,6 +1,6 @@
from django.contrib.sitemaps import Sitemap from django.contrib.sitemaps import Sitemap
from main.models import Package, News from main.models import Package, News
from packages.views import get_group_information from packages.views import get_group_info
class PackagesSitemap(Sitemap): class PackagesSitemap(Sitemap):
changefreq = "weekly" changefreq = "weekly"
@ -30,7 +30,7 @@ class PackageGroupsSitemap(Sitemap):
priority = "0.4" priority = "0.4"
def items(self): def items(self):
return get_group_information() return get_group_info()
def lastmod(self, obj): def lastmod(self, obj):
return obj['last_update'] return obj['last_update']