Recent updates refactor

Pull out a few helpful objects and functions for use later elsewhere.

Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Dan McGee 2011-06-29 12:05:07 -05:00
parent f3262790b3
commit c5308b7583
2 changed files with 48 additions and 25 deletions

View File

@ -91,4 +91,39 @@ def set_created_field(sender, **kwargs):
if hasattr(obj, 'created') and not obj.created: if hasattr(obj, 'created') and not obj.created:
obj.created = datetime.utcnow() obj.created = datetime.utcnow()
def groupby_preserve_order(iterable, keyfunc):
'''Take an iterable and regroup using keyfunc to determine whether items
belong to the same group. The order of the iterable is preserved and
similar keys do not have to be consecutive. This means the earliest
occurrence of a given key will determine the order of the lists in the
returned list.'''
seen_keys = {}
result = []
for item in iterable:
key = keyfunc(item)
group = seen_keys.get(key, None)
if group is None:
group = []
seen_keys[key] = group
result.append(group)
group.append(item)
return result
class PackageStandin(object):
'''Resembles a Package object, and has a few of the same fields, but is
really a link to a pkgbase that has no package with matching pkgname.'''
def __init__(self, package):
self.package = package
self.pkgname = package.pkgbase
def __getattr__(self, name):
return getattr(self.package, name)
def get_absolute_url(self):
return '/packages/%s/%s/%s/' % (
self.repo.name.lower(), self.arch.name, self.pkgbase)
# vim: set ts=4 sw=4 et: # vim: set ts=4 sw=4 et:

View File

@ -1,7 +1,7 @@
from operator import attrgetter from operator import attrgetter
from main.models import Arch, Package, Repo from main.models import Arch, Package, Repo
from main.utils import cache_function from main.utils import cache_function, groupby_preserve_order, PackageStandin
class RecentUpdate(object): class RecentUpdate(object):
def __init__(self, packages): def __init__(self, packages):
@ -35,18 +35,12 @@ def package_links(self):
for package in self.packages: for package in self.packages:
yield package yield package
else: else:
# time to fake out the template, this is a tad dirty # fake out the template- this is slightly hacky but yields one
arches = set(pkg.arch for pkg in self.others) # 'package-like' object per arch which is what the normal loop does
for arch in arches: arches = set()
url = '/packages/%s/%s/%s/' % ( for package in self.others:
self.repo.name.lower(), arch.name, self.pkgbase) if package.arch not in arches and not arches.add(package.arch):
package_stub = { yield PackageStandin(package)
'pkgname': self.pkgbase,
'arch': arch,
'repo': self.repo,
'get_absolute_url': url
}
yield package_stub
@cache_function(300) @cache_function(300)
def get_recent_updates(number=15): def get_recent_updates(number=15):
@ -59,20 +53,14 @@ def get_recent_updates(number=15):
for arch in Arch.objects.all(): for arch in Arch.objects.all():
pkgs += list(Package.objects.normal().filter( pkgs += list(Package.objects.normal().filter(
arch=arch).order_by('-last_update')[:fetch]) arch=arch).order_by('-last_update')[:fetch])
pkgs.sort(key=attrgetter('last_update')) 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 = [] updates = []
while len(pkgs) > 0: for group in grouped:
pkg = pkgs.pop() update = RecentUpdate(group)
in_group = lambda x: pkg.repo == x.repo and pkg.pkgbase == x.pkgbase
samepkgs = [other for other in pkgs if in_group(other)]
samepkgs.append(pkg)
# now remove all the packages we just pulled out
pkgs = [other for other in pkgs if other not in samepkgs]
update = RecentUpdate(samepkgs)
updates.append(update) updates.append(update)
return updates[:number] return updates[:number]