evorepo/public/utils.py
Dan McGee f579f88e17 Don't link to a one-element listing page from recent updates
If a package is built as a split package where pkgname != pkgbase, but
only one actual split package is produced, the link on the recent update
screen requires an extra click to get to the single package. Fix this by
linking directly to the package itself.

(Examples in current repos: ntfs-3g, python2-south)

Signed-off-by: Dan McGee <dan@archlinux.org>
2013-03-11 09:40:38 -05:00

91 lines
3.4 KiB
Python

from collections import defaultdict
from operator import attrgetter
from main.models import Arch, Repo, Package
from main.utils import cache_function, groupby_preserve_order, PackageStandin
class RecentUpdate(object):
def __init__(self, packages):
if len(packages) == 0:
raise Exception
first = packages[0]
self.pkgbase = first.pkgbase
self.repo = first.repo
self.version = ''
self.classes = set()
self.classes.add(self.repo.name.lower())
if self.repo.testing:
self.classes.add('testing')
if self.repo.staging:
self.classes.add('staging')
packages = sorted(packages, key=attrgetter('arch', 'pkgname'))
# split the packages into two lists. we need to prefer packages
# matching pkgbase as our primary, and group everything else in other.
self.packages = [pkg for pkg in packages if pkg.pkgname == pkg.pkgbase]
self.others = [pkg for pkg in packages if pkg.pkgname != pkg.pkgbase]
if self.packages:
version = self.packages[0].full_version
if all(version == pkg.full_version for pkg in self.packages):
self.version = version
elif self.others:
version = self.others[0].full_version
if all(version == pkg.full_version for pkg in self.others):
self.version = version
def package_links(self):
'''Returns either actual packages or package-standins for virtual
pkgbase packages.'''
if self.packages:
# we have real packages- just yield each in sequence
for package in self.packages:
yield package
else:
# fake out the template- this is slightly hacky but yields one
# 'package-like' object per arch which is what the normal loop does
by_arch = defaultdict(list)
for package in self.others:
by_arch[package.arch].append(package)
for arch, packages in by_arch.items():
if len(packages) == 1:
yield packages[0]
else:
yield PackageStandin(packages[0])
def __unicode__(self):
return "RecentUpdate '%s %s' <%d packages>" % (
self.pkgbase, self.version, len(self.packages))
@cache_function(62)
def get_recent_updates(number=15, testing=True, staging=False):
repos = Repo.objects.all()
if not testing:
repos = repos.exclude(testing=True)
if not staging:
repos = repos.exclude(staging=True)
# This is a bit of magic. We are going to show 15 on the front page, but we
# want to try and eliminate cross-architecture wasted space. Pull enough
# packages that we can later do some screening and trim out the fat.
pkgs = []
# grab a few extra so we can hopefully catch everything we need
fetch = number * 6
for arch in Arch.objects.all():
pkgs += list(Package.objects.normal().filter(
arch=arch, repo__in=repos).order_by('-last_update')[:fetch])
pkgs.sort(key=attrgetter('last_update'), reverse=True)
same_pkgbase_key = lambda x: (x.repo.name, x.pkgbase)
grouped = groupby_preserve_order(pkgs, same_pkgbase_key)
updates = []
for group in grouped:
update = RecentUpdate(group)
updates.append(update)
return updates[:number]
# vim: set ts=4 sw=4 et: