File: pkgwalk

package info (click to toggle)
python-debian 0.1.18%2Bsqueeze1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 616 kB
  • ctags: 642
  • sloc: python: 4,141; makefile: 49
file content (121 lines) | stat: -rwxr-xr-x 3,522 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/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.

# Navigate among related Debian packages

import sys

# Requires python-extractor, python-magic and python-debtags
from debian import debtags
import re
from optparse import OptionParser
import apt


VERSION="0.1"

class Parser(OptionParser):
	def __init__(self, *args, **kwargs):
		OptionParser.__init__(self, *args, **kwargs)

	def error(self, msg):
		sys.stderr.write("%s: error: %s\n\n" % (self.get_prog_name(), msg))
		self.print_help(sys.stderr)
		sys.exit(2)

if __name__ == '__main__':
	parser = Parser(usage="usage: %prog [options] pkgname",
			version="%prog "+ VERSION,
			description="walk through Debian packages")
	parser.add_option("--tagdb", default="/var/lib/debtags/package-tags", help="Tag database to use (default: %default)")

	(options, args) = parser.parse_args()

	if len(args) == 0:
		parser.error("Please provide the name of an initial package")

	# Read full database 
	db = debtags.DB()
	tag_filter = re.compile(r"^special::.+$|^.+::TODO$")
	db.read(open(options.tagdb, "r"), lambda x: not tag_filter.match(x))

	apt_cache = apt.Cache()

	# Maximum number of previous packages to remember 
	maxlen = 5
	# Initial package selection
	trail = [ args[0] ]

	# 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.tags_of_package(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.iter_packages_tags():
			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.tags_of_package(pkg):
				if tag in tagscores:
					score += tagscores[tag]
			return score
		
		# Show the first 20 packages in reverse score order
		#display = sorted(nextpkgs - set(trail), key=pkgscore, reverse=True)[:20]
		display = sorted(nextpkgs, key=pkgscore, reverse=True)[:20]
		for num, pkg in enumerate(display):
			aptpkg = apt_cache[pkg]
			desc = aptpkg.raw_description.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"


# vim:set ts=4 sw=4: