#!/usr/bin/env python '''Generate a HTML index page listing all applications in known repositories''' __copyright__ = 'Copyright (C) 2006 Tommi Komulainen ' __license__ = '''\ 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. ''' __version__ = '0.20060716' __all__ = [] # TODO # - use rfc822 parser (to get the multiline description) # - instead of configuring repository name, it could be taken from Release file # - figure out a way to collect more metadata # - make it look nice # - get rid of apt_pkg or try to use it for downloading etc. import apt_pkg import urllib import string import gzip import sys import locale from cStringIO import StringIO class Repository: def __init__(self, name, address, distribution='mistral', components=['user']): self.name = name self.address = address.rstrip('/') self.distribution = distribution self.components = components or [] def as_sources_list(self): return '# %s\ndeb %s %s %s' % (self.name, self.address, self.distribution, ' '.join(self.components)) ARCHITECTURES = ('armel', 'all') REPOSITORIES = [ Repository(name='Nokia Tableteer Certified', address='http://catalogue.tableteer.nokia.com/certified'), Repository(name='Nokia Tableteer Non-Certified', address='http://catalogue.tableteer.nokia.com/non-certified'), Repository(name='Maemo Garage', address='http://repository.maemo.org/contrib/', components=['free', 'non-free']), Repository(name='Maemo repository', address='http://repository.maemo.org/', components=['free', 'non-free']), Repository(name='FBReader', address='http://only.mawhrin.net/fbreader/maemo/'), Repository(name='Kernel Concepts', address='http://downloads.kernelconcepts.de/maemo2', components=['free']), Repository(name='Maemo Hackers', address='http://maemo-hackers.org/apt/', components=['main']), Repository(name='MUlliNER.ORG Repository', address='http://www.mulliner.org/nokia770/repository/', distribution='maemo2', components=['free']), Repository(name='Oak Court Repository', address='http://www.oakcourt.dyndns.org/maemo/', distribution='./', components=None), Repository(name='Sardine', address='http://repository.maemo.org', distribution='sardine', components=['main', 'non-free']), Repository(name='OpenedHand', address='http://maemo.o-hand.com/packages', distribution='mistral/', components=None) ] def load_packages_list(repo): assert repo.address is not None assert repo.distribution is not None index_urls = [] if repo.components: dists_url = repo.address + '/dists/' + repo.distribution for arch in ARCHITECTURES: for comp in repo.components: url = dists_url + '/%s/binary-%s/Packages.gz' % (comp, arch) index_urls.append(url) else: url = repo.address + '/' + repo.distribution + 'Packages.gz' index_urls.append(url) packages_by_name = {} opener = urllib.URLopener() for url in index_urls: print >>sys.stderr, 'Fetching', url, '...', try: buf = opener.open(url).read() fp = gzip.GzipFile(fileobj=StringIO(buf)) except IOError: print >>sys.stderr, 'FAILED' continue package = None for line in fp: line = line.rstrip() if not line: if package: packages_by_name[package['name']] = package package = None continue if line[0] in string.letters and ':' in line: hdr,val = line.split(':', 1) hdr = hdr.lower() val = val.lstrip() if hdr == 'package': assert package is None package = {} package['name'] = val elif hdr == 'version': if package is not None: prev_package = packages_by_name.get(package['name']) if prev_package: prev_version = prev_package['version'] if apt_pkg.VersionCompare(prev_version, val) > 0: package['version'] = val else: package = None else: package['version'] = val elif hdr in ('section', 'description', 'architecture'): if package is not None: package[hdr] = val print >>sys.stderr, 'OK' return packages_by_name def print_sections(sections, packages_by_section): def package_cmp_name(a, b): return locale.strcoll(a['name'].lower(), b['name'].lower()) def package_cmp_description(a, b): return locale.strcoll(a['description'].lower(), b['description'].lower()) sections.sort() for section in sections: print '

%s

' % section packages = packages_by_section[section] packages.sort(package_cmp_description) for p in packages: repo = p['repository'] print '
' print '
%(description)s
' % p print '
%(name)s %(version)s
' % p print '
%s
' % repo.name print '
' print def main(): locale.setlocale(locale.LC_ALL, None) apt_pkg.InitConfig() apt_pkg.InitSystem() packages_by_section = {} for repo in REPOSITORIES: packages = load_packages_list(repo) if not packages: continue for package in packages.values(): package['repository'] = repo sectionpkgs = packages_by_section.setdefault(package['section'], []) sectionpkgs.append(package) sections = packages_by_section.keys() user_sections = filter(lambda s: s.startswith('user/'), sections) other_sections = filter(lambda s: not s.startswith('user/'), sections) print ''' ''' print '

User packages

' print_sections(user_sections, packages_by_section) print '
' print '

Other packages

' print_sections(other_sections, packages_by_section) print '
' print '

sources.list

' print '
'
    for repo in REPOSITORIES:
	print repo.as_sources_list()
	print
    print '
' print ''' ''' if __name__ == '__main__': main()