#!/usr/bin/python
#
# Copyright (C) 2007 Enrico Zini <enrico@debian.org>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
# From python-debian
from debian_bundle import debtags
# From python-apt
import apt
import re
aptCache = apt.Cache()
# Read the Debtags database
db = debtags.DB()
tagFilter = re.compile(r"^special::.+$|^.+::TODO$")
db.read(open(options.tagdb, "r"), lambda x: not tagFilter.match(x))
# Maximum number of previous packages to remember
maxlen = 3
# Initial package selection
trail = [ 'debtags' ]
# Loop until the user chooses to quit
done = False
while not done:
# Compute a package weight according to how old it is in the
# trail
pkgweight = {}
for idx, pkg in enumerate(trail):
pkgweight[pkg] = 1.-(idx/maxlen)
# For every tag, find the number of packages in trail that have the tag
tagscores = {}
for pkg in trail:
for tag in db.tagsOfPackage(pkg):
if tag in tagscores:
tagscores[tag] += pkgweight[pkg]
else:
tagscores[tag] = pkgweight[pkg]
# Divide every tag score by the number of packages in the trail,
# obtaining a 'tag weight'. A package can be later scored by summing
# the weight of all its tags.
for tag in tagscores.iterkeys():
tagscores[tag] = float(tagscores[tag]) / float(len(trail))
# Find the merged tagset of the packages in trail
trailtags = set(tagscores.keys())
# Get the list of packages whose tagsets intersect the trail tagset
nextpkgs = set()
for pkg, tags in db.iterPackagesTags():
if trailtags & tags:
nextpkgs.add(pkg)
# Score every package by the sum of the weight of its tags
def pkgscore(pkg):
score = 0.0
for tag in db.tagsOfPackage(pkg):
if tag in tagscores:
score += tagscores[tag]
return score
# Show the first 20 packages in reverse score order
display = sorted(nextpkgs, key=pkgscore, reverse=True)[:20]
for num, pkg in enumerate(display):
aptpkg = aptCache[pkg]
desc = aptpkg.rawDescription.split("\n")[0]
print "%2d) %s - %s" % (num + 1, pkg, desc)
# Ask the user to choose a new package
while True:
ans = raw_input("> ").strip()
if ans[0] == 'q':
done = True
break
elif ans.isdigit():
num = int(ans) - 1
if num < len(display):
# TODO: on a different kind of interface, display the full
# description of pkg
trail = [display[num]] + trail[:maxlen]
break
else:
print "The number is too high"