summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO28
-rw-r--r--db.sql132
-rwxr-xr-xgen-patch-info.py24
-rwxr-xr-xpagehandler.py45
-rwxr-xr-xpatchtracker/Conf.py2
-rw-r--r--patchtracker/DB.py171
-rwxr-xr-xpatchtracker/SourceArchive.py65
-rwxr-xr-xpatchtracker/Writers.py23
-rw-r--r--templates/frontpage.tmpl12
-rw-r--r--templates/letter_toc.tmpl2
-rwxr-xr-xtemplates/package_vers.tmpl20
11 files changed, 402 insertions, 122 deletions
diff --git a/TODO b/TODO
index f0c914f..af23e34 100644
--- a/TODO
+++ b/TODO
@@ -2,16 +2,10 @@ welcome to the TODO file.
== short-range TODO ==
-fix the patch display/markup
+remove hardcoded url parsing
- given the disk space requirements, the patches are not automatically
- generated any longer. an as-of-yet unwritten cgi script will handle
- such requests.
-
-don't nuke/reinit the whole patch tracking tree
-
- this also implies that some kind of garbage collection takes place
- to remove versions that are no longer being tracked
+ pagehandler currently assumes installation under a certain subdir,
+ which isn't at all necessary.
better handling of more exotic patch systems
@@ -22,8 +16,19 @@ better handling of more exotic patch systems
code cleanup from really ugly stuff (look for XXX)
+dead code removal/cleanup
+
+ after switching a few design decisions, there's some code that's no longer
+ used or should be renamed/moved (i.e. writers/templates)
+
== medium-range TODO ==
+review db design
+
+ the db schema design is most likely less than optimal, the use of triggers
+ to emulate foreign keys is novel but likely we can remove a few columns and
+ use rowids instead, and possibly lower/optimise the remaining queries.
+
remove all the os.system calls
lots of temporary ducttape via os.system that should go away
@@ -35,8 +40,9 @@ make prettier pages
decide how much should be cgi-based and how much should be written
- there's no reason why the other pages couldn't also be generated from
- a cgi, if we desired.
+ there's no reason why the entire system can't be generated via cgi-based
+ accessing, but the question is whether it should be, or whether certain
+ componenets should remain static.
== long-range TODO ==
diff --git a/db.sql b/db.sql
index a7fe50e..26c9667 100644
--- a/db.sql
+++ b/db.sql
@@ -1,4 +1,128 @@
-create table packages ( id int, package varchar(256), format varchar(32), diffgz varchar(1024), loc varchar(1024), type varchar(32), version varchar(256), updated int );
-create table releases ( id int, name varchar(32), md5sum varchar(32), updated int );
-create table components ( id int, name varchar(32), updated int );
-create table pkg_rel ( rel_id int, comp_id int, pkg_id int );
+CREATE TABLE packages (
+ id int UNIQUE NOT NULL,
+ name text NOT NULL,
+ version text NOT NULL,
+ format text NOT NULL,
+ loc text NOT NULL,
+ diffgz_name text DEFAULT NULL,
+ diffgz_size int DEFAULT NULL,
+ diffgz_md5sum varchar(32) DEFAULT NULL
+);
+
+CREATE TABLE suites (
+ id int UNIQUE NOT NULL,
+ name text UNIQUE NOT NULL PRIMARY KEY
+);
+
+CREATE TABLE components (
+ id int UNIQUE NOT NULL,
+ name text PRIMARY KEY
+);
+
+CREATE TABLE package_rel_map (
+ package_id int NOT NULL
+ CONSTRAINT fk_package_id REFERENCES packages(id),
+ suite_id int NOT NULL
+ CONSTRAINT fk_suite_id REFERENCES suites(id) ON DELETE CASCADE,
+ component_id int NOT NULL
+ CONSTRAINT fk_component_id REFERENCES components(id)
+);
+
+-- sqlite doesn't actually implement FK constraints, therefore we
+-- help out a little and do it ourselves via triggers
+
+-- before insert on the package relation mapping, catch invalid references
+
+CREATE TRIGGER fki_package_rel_map_suite_id_suites_id
+ BEFORE INSERT ON [package_rel_map]
+ FOR EACH ROW BEGIN
+ SELECT RAISE(ROLLBACK, 'INSERT on "package_rel_map" violates FK constraint on "suites.id"')
+ WHERE (SELECT id FROM suites WHERE id = NEW.suite_id) IS NULL;
+ END;
+
+CREATE TRIGGER fki_package_rel_map_package_id_packages_id
+ BEFORE INSERT ON [package_rel_map]
+ FOR EACH ROW BEGIN
+ SELECT RAISE(ROLLBACK, 'INSERT on "package_rel_map" violates FK constraint on "packages.id"')
+ WHERE (SELECT id FROM packages WHERE id = NEW.package_id) IS NULL;
+ END;
+
+CREATE TRIGGER fki_package_rel_map_component_id_components_id
+ BEFORE INSERT ON [package_rel_map]
+ FOR EACH ROW BEGIN
+ SELECT RAISE(ROLLBACK, 'INSERT on "package_rel_map" violates FK constraint on "components.id"')
+ WHERE (SELECT id FROM components WHERE id =NEW.component_id) IS NULL;
+ END;
+
+-- the same but for updates
+
+CREATE TRIGGER fku_package_rel_map_suite_id_suites_id
+ BEFORE UPDATE ON [package_rel_map]
+ FOR EACH ROW BEGIN
+ SELECT RAISE(ROLLBACK, 'update on "package_rel_map" violates FK constraint on "suites.id"')
+ WHERE (SELECT id FROM suites WHERE id = NEW.suite_id) IS NULL;
+ END;
+
+CREATE TRIGGER fku_package_rel_map_package_id_packages_id
+ BEFORE UPDATE ON [package_rel_map]
+ FOR EACH ROW BEGIN
+ SELECT RAISE(ROLLBACK, 'update on "package_rel_map" violates FK constraint on "packages.id"')
+ WHERE (SELECT id FROM packages WHERE id = NEW.package_id) IS NULL;
+ END;
+
+CREATE TRIGGER fku_package_rel_map_component_id_components_id
+ BEFORE UPDATE ON [package_rel_map]
+ FOR EACH ROW BEGIN
+ SELECT RAISE(ROLLBACK, 'update on "package_rel_map" violates FK constraint on "components.id"')
+ WHERE (SELECT id FROM components WHERE id=NEW.component_id) IS NULL;
+ END;
+
+-- when a package/component/suite id is deleted, clean up any references
+-- that would otherwise be orphaned
+
+CREATE TRIGGER fkdc_package_rel_map_suite_id_suites_id
+ BEFORE DELETE ON suites
+ FOR EACH ROW BEGIN
+ DELETE FROM package_rel_map WHERE package_rel_map.suite_id = OLD.id;
+ END;
+
+CREATE TRIGGER fkdc_package_rel_map_component_id_components_id
+ BEFORE DELETE ON components
+ FOR EACH ROW BEGIN
+ DELETE FROM package_rel_map WHERE package_rel_map.component_id = OLD.id;
+ END;
+
+CREATE TRIGGER fkdc_package_rel_map_package_id_packages_id
+ BEFORE DELETE ON packages
+ FOR EACH ROW BEGIN
+ DELETE FROM package_rel_map WHERE package_rel_map.package_id = OLD.id;
+ END;
+
+-- when a package relation mapping is deleted or updated, delete the package
+-- record for the old relation if no other references to that package exist
+
+CREATE TRIGGER fkdc_packages_id_package_rel_map_package_id
+ BEFORE DELETE ON package_rel_map
+ FOR EACH ROW BEGIN
+ DELETE FROM packages WHERE packages.id = OLD.package_id
+ AND (SELECT package_id FROM package_rel_map
+ WHERE package_id = OLD.package_id AND rowid != OLD.rowid)
+ IS NULL;
+ END;
+
+CREATE TRIGGER fku_package_rel_map_prune_packages_package_id
+ BEFORE UPDATE ON [package_rel_map]
+ FOR EACH ROW BEGIN
+ DELETE FROM packages WHERE packages.id = OLD.package_id
+ AND (OLD.package_id != NEW.package_id)
+ AND (SELECT package_id FROM package_rel_map
+ WHERE package_id = OLD.package_id AND rowid != OLD.rowid)
+ IS NULL;
+ END;
+
+INSERT INTO packages VALUES (0,'','','','',NULL,NULL,NULL);
+
+INSERT INTO suites VALUES (0,'');
+
+INSERT INTO components VALUES (0,'');
+
diff --git a/gen-patch-info.py b/gen-patch-info.py
index 618179a..afe6b3e 100755
--- a/gen-patch-info.py
+++ b/gen-patch-info.py
@@ -3,12 +3,14 @@
import os
import sys
import getopt
+import errno
import patchtracker.Conf as Conf
-from patchtracker.Writers import LetterTocWriter, FrontPageWriter, PackageVersWriter
-from patchtracker.SourceArchive import Archive, SourcePackage, SourcePackageIndex
+from patchtracker.SourceArchive import Archive, SourcePackage
+from patchtracker.DB import PatchTrackerDB
if __name__ == '__main__':
+ db = PatchTrackerDB()
os.system("cheetah compile templates/skeleton")
opts,args = getopt.getopt(sys.argv[1:], "s:p:")
suites = None
@@ -22,20 +24,24 @@ if __name__ == '__main__':
a = Archive(Conf.archive_root)
# just for now until development stablizes
#os.system("rm -rf "+Conf.output_dir)
- #os.mkdir(Conf.output_dir)
+ try:
+ os.mkdir(Conf.output_dir)
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise e
print a
- master_index = SourcePackageIndex()
for s in a.suites(filter=suites):
print "suite: ",s
+ db.saveSuite(s)
for c in a.components(s):
print "\tcomponent:",c
+ db.saveComponent(c)
for p in a.sourcepackages(s, c, filter=packages):
print "\t\tpackage:",p
- PackageVersWriter(p, s)
- master_index.ins(p,s)
+ db.saveSourcePackage(p)
+ db.relateSourcePackage(p,suite=s,component=c)
os.system("cp -a "+Conf.static_dir+"/* "+Conf.output_dir)
- FrontPageWriter(master_index)
- for letter,stuff in master_index.indices():
- LetterTocWriter(letter,stuff)
+
+ db.finalize()
diff --git a/pagehandler.py b/pagehandler.py
index 858534b..9fc6d9c 100755
--- a/pagehandler.py
+++ b/pagehandler.py
@@ -5,17 +5,21 @@ import cgi
import os
import sys
import patchtracker.Conf as Conf
-from patchtracker.Writers import ErrorTemplate, PatchTemplate
+from patchtracker.Writers import ErrorTemplate, PatchTemplate, PackageVersTemplate, LetterTocTemplate, FrontPageTemplate
from patchtracker.DiffGzHandler import DiffGzHandler
+import patchtracker.DB as DB
+from patchtracker.DB import PatchTrackerDB
import pygments
from pygments.lexers import DiffLexer
from pygments.formatters import HtmlFormatter
class CmdHandler:
def __init__(self, req_uri):
+ self.db = PatchTrackerDB()
args = req_uri.split("/")
+ self.cmd = args[2]
# XXX this assumes http://site/foo/patch/adsfadf
- if args[2] == "patch":
+ if self.cmd == "patch":
patchtype,mode,pkgname,version = args[3:7]
self.parsemode(mode)
dh = self.make_diffhandler(pkgname,version)
@@ -32,8 +36,21 @@ class CmdHandler:
self.error("unhandled patch type '%s'"%(patchtype))
self.pkgname = pkgname
self.version = version
+ elif self.cmd == "package":
+ self.db.setFactory(DB.srcpkg_factory)
+ self.name = args[3]
+ self.version = args[4]
+ self.srcpkg = self.db.findSourcePackage(self)
+ elif self.cmd == "index":
+ if len(args) < 4 or not len(args[3]):
+ self.error("please provide a letter on which to index")
+ else:
+ self.letter = args[3]
+ self.toc = self.db.findLetterToc(self.letter)
else:
- self.error("unhandled command: '%s'"%(args[2]))
+ # XXX better way to set up "frontpage"
+ self.index = self.db.findMasterIndex()
+ self.cmd = "frontpage"
# XXX this assumes to much hard coded, but until there's a faster
# XXX (i.e. database) way to query sourcepackage/diffs it will
@@ -67,13 +84,25 @@ class CmdHandler:
sys.exit(1)
def output(self):
- if self.mode == "dl":
- print "Content-Type: text/x-diff\n\n"
- print self.content
- else:
+ if self.cmd == "patch":
+ if self.mode == "dl":
+ print "Content-Type: text/x-diff\n\n"
+ print self.content
+ else:
+ print "Content-Type: text/html\n\n"
+ print PatchTemplate(pkg=self.pkgname,vers=self.version,patch=self.content,name=self.patchname)
+ elif self.cmd == "package":
+ print "Content-Type: text/html\n\n"
+ print PackageVersTemplate(self.srcpkg,"XXX FIXME")
+ elif self.cmd == "index":
+ print "Content-Type: text/html\n\n"
+ print LetterTocTemplate(self.letter, self.toc)
+ elif self.cmd == "frontpage":
print "Content-Type: text/html\n\n"
- print PatchTemplate(pkg=self.pkgname,vers=self.version,patch=self.content,name=self.patchname)
+ print FrontPageTemplate(self.index)
if __name__ == "__main__":
uri = os.getenv("REQUEST_URI")
+ if not uri:
+ uri = sys.argv[1]
CmdHandler(uri).output()
diff --git a/patchtracker/Conf.py b/patchtracker/Conf.py
index bc095b2..c4ec803 100755
--- a/patchtracker/Conf.py
+++ b/patchtracker/Conf.py
@@ -5,3 +5,5 @@ template_dir = './templates'
static_dir = './static'
#root_url = 'http://people.debian.org/~seanius/pts/patches'
root_url = '/patches'
+database = 'pt.db'
+sqlschema = 'db.sql'
diff --git a/patchtracker/DB.py b/patchtracker/DB.py
index 2f1b208..d74744d 100644
--- a/patchtracker/DB.py
+++ b/patchtracker/DB.py
@@ -1,68 +1,171 @@
from pysqlite2 import dbapi2 as sqlite
-import Conf as Conf
+import Conf
import os
import errno
-import time
+import patchtracker.SourceArchive as SourceArchive
-class PatchTrackerDB:
- db = None
- now = None
- cursor = None
+def srcpkg_factory(cursor, row):
+ d = {}
+ for idx, col in enumerate(cursor.description):
+ d[col[0]] = row[idx]
+
+ info = {}
+ info['Files'] = []
+ if d['diffgz_name']:
+ diffgz = {'name':d['diffgz_name'], 'size':d['diffgz_size'],
+ 'md5sum':d['diffgz_md5sum'] }
+ info['Files'].append(diffgz)
+
+ colmap = {'name':'Package','version':'Version','format':'Format',
+ 'loc':'Directory'}
+
+ for col,field in colmap.iteritems():
+ info[field] = d[col]
+ return SourceArchive.SourcePackage(info)
+
+class PatchTrackerDB:
def __init__(self, dbname=Conf.database):
- self.now = int(time.time())
self.db = sqlite.connect(dbname)
- self.cursor = self.db.cursor()
- self.cursor.execute("SELECT * FROM sqlite_master WHERE name='packages'")
- if not self.cursor.fetchone():
+ cursor = self.db.cursor()
+ cursor.execute("SELECT * FROM sqlite_master WHERE name='packages'")
+ if not cursor.fetchone():
print "repopulating empty database..."
+ nextcmd = ""
for l in file(Conf.sqlschema).readlines():
- self.cursor.execute(l)
+ if len(l.strip()):
+ nextcmd += " " + l.strip()
+ else:
+ print "exec: %s"%(nextcmd)
+ cursor.execute(nextcmd)
+ nextcmd = ""
+
+ def setFactory(self, factory):
+ self.db.row_factory = factory
def findSourcePackage(self, srcpkg):
- q = "SELECT * FROM packages WHERE package = ? AND version = ?"
- self.cursor.execute(q, (srcpkg.name, srcpkg.version))
- s = self.cursor.fetchone()
+ q = "SELECT * FROM packages WHERE name=? AND version=?"
+ cursor = self.db.cursor()
+ cursor.execute(q, (srcpkg.name, srcpkg.version))
+ s = cursor.fetchone()
return s
def saveSourcePackage(self, srcpkg):
+ cursor = self.db.cursor()
s = self.findSourcePackage(srcpkg)
+
+ queryargs = (srcpkg.name,srcpkg.format,srcpkg.loc,
+ srcpkg.version,srcpkg.diffgz_name,srcpkg.diffgz_size,
+ srcpkg.diffgz_md5sum)
if not s:
- print "creating new record for",srcpkg
- q = "INSERT INTO packages (package,format,diffgz,loc,type,version,updated) VALUES (?,?,?,?,?,?,?)"
+ #print "creating new record for",srcpkg
+ q = "INSERT INTO packages (id,name,format,loc,version,\
+ diffgz_name,diffgz_size,diffgz_md5sum)\
+ VALUES ((SELECT MAX(id)+1 FROM packages),?,?,?,?,?,?,?)"
else:
- print "updating record for",srcpkg
- q = "UPDATE packages SET package=?,format=?,diffgz=?,loc=?,type=?,version=?,updated=?"
- self.cursor.execute(q, (srcpkg.name,srcpkg.format,srcpkg.diffgz,srcpkg.loc,srcpkg.type,srcpkg.version,self.now))
+ #print "updating record for",srcpkg
+ q = "UPDATE packages SET name=?,format=?,loc=?,version=?,\
+ diffgz_name=?,diffgz_size=?,diffgz_md5sum=?\
+ WHERE name=? AND version=?"
+ queryargs += (srcpkg.name, srcpkg.version)
+ cursor.execute(q, queryargs)
- def findRelease(self, release)
- raise Exception("not yet implemented")
+ def findSuite(self, suite):
+ q = "SELECT * FROM suites WHERE name = ?"
+ cursor = self.db.cursor()
+ cursor.execute(q, (suite,))
+ return cursor.fetchone()
- def saveRelease(self, release)
- raise Exception("not yet implemented")
+ def saveSuite(self, suite):
+ s = self.findSuite(suite)
+ if not s:
+ q = "INSERT INTO suites (id,name) \
+ VALUES ((SELECT MAX(id)+1 FROM suites),?)"
+ cursor = self.db.cursor()
+ cursor.execute(q, (suite,))
- def findComponent(self, release, component):
- raise Exception("not yet implemented")
+ def findComponent(self, component):
+ q = "SELECT * FROM components WHERE name = ?"
+ cursor = self.db.cursor()
+ cursor.execute(q, (component,))
+ return cursor.fetchone()
def saveComponent(self, component):
- raise Exception("not yet implemented")
-
- def relateComponentToSourcePackage(self, component, srcpkg):
- raise Exception("not yet implemented")
+ c = self.findComponent(component)
+ if not c:
+ q = "INSERT INTO components (id,name) \
+ VALUES ((SELECT MAX(id)+1 FROM components),?)"
+ cursor = self.db.cursor()
+ cursor.execute(q, (component,))
+
+ def findLetterToc(self, letter):
+ oldfactory = self.db.row_factory
+ dcursor = self.db.cursor()
+ dq = "SELECT id,name FROM suites"
+ dcursor.execute(dq)
+ suites = {}
+ for id,suite in dcursor.fetchall():
+ suites[id] = suite
+
+ self.db.row_factory = srcpkg_factory
+ cursor = self.db.cursor()
+ toc = SourceArchive.SourcePackageIndex()
+ for s,v in suites.iteritems():
+ q = "SELECT * FROM packages AS p,package_rel_map AS m \
+ WHERE p.name like ? AND p.id = m.package_id and m.suite_id = ?"
+ cursor.execute(q, (letter+"%", s))
+ # use srcpkg_factory to fetch sourcepackages, once per suite
+ for srcpkg in cursor.fetchall():
+ toc.ins(srcpkg, v)
+ self.db.row_factory = oldfactory
+ return toc.getletter(letter)
+
+ def findMasterIndex(self):
+ cursor = self.db.cursor()
+ toc = SourceArchive.MasterIndex()
+ q = "SELECT name FROM packages WHERE id > 0"
+ cursor.execute(q)
+ for name in cursor.fetchall():
+ # XXX find a better way to do this..., probably just store metainfo
+ # XXX in the db and update it via triggers
+ toc.add(name[0])
+ return toc
+
+ def findSourcePackageRelation(self, srcpkg, suite):
+ q = "SELECT * FROM packages AS p,suites AS s,package_rel_map AS m \
+ WHERE p.name=? AND s.name=? AND m.package_id=p.id \
+ AND m.suite_id=s.id"
+ cursor = self.db.cursor()
+ cursor.execute(q, (srcpkg.name, suite))
+ return cursor.fetchone()
+
+ def relateSourcePackage(self, srcpkg, suite, component):
+ s = self.findSourcePackageRelation(srcpkg, suite)
+ if not s:
+ s = self.findSourcePackage(srcpkg)
+ q = "INSERT INTO package_rel_map (package_id,suite_id,component_id) \
+ VALUES (?, \
+ (SELECT id FROM suites WHERE name=?), \
+ (SELECT id FROM components WHERE name=?))"
+ else:
+ q = "UPDATE package_rel_map SET package_id=? \
+ WHERE suite_id=(SELECT id FROM suites WHERE name=?) \
+ AND component_id=(SELECT id FROM components WHERE name=?)"
+ cursor = self.db.cursor()
+ cursor.execute(q, (s[0], suite, component))
def finalize(self):
- # remove cruft in a rather lazy way
- self.cursor.execute("DELETE FROM packages WHERE updated < ?", (self.now,))
self.db.commit()
+
+ def __del__(self):
+ self.finalize()
if __name__ == "__main__":
print "patch tracker db testing"
d = PatchTrackerDB(dbname="foo.db")
- from SourceArchive import SourcePackage
- sp = SourcePackage({'Package':'foo','Format':'blah','Directory':'/foo','Version':'1.2.3.4','Files':[]})
+ sp = SourceArchive.SourcePackage({'Package':'foo','Format':'blah','Directory':'/foo','Version':'1.2.3.4','Files':[]})
d.saveSourcePackage(sp)
d.finalize()
-
diff --git a/patchtracker/SourceArchive.py b/patchtracker/SourceArchive.py
index 1f12001..a0aab1b 100755
--- a/patchtracker/SourceArchive.py
+++ b/patchtracker/SourceArchive.py
@@ -45,49 +45,66 @@ class Archive:
def __str__(self):
return "Archive rooted at "+self.root
-class SourcePackage:
- name = None
- format = None
- diffgz = None
- loc = None
- type = "Native"
- version = None
- # todo
- vcs = {}
+# XXX maybe there's a better place/way for this
+def getidx(letter):
+ name = str(letter)
+ if len(name) < 4 or name[0:3] != "lib":
+ return name[0]
+ else:
+ return name[0:4]
+class SourcePackage:
def __init__(self, info):
+ self.diffgz_name = None
+ self.diffgz_size = None
+ self.diffgz_md5sum = None
+ self.diffgz = None
+ self.type = "Native"
self.name = info['Package']
self.format = info['Format']
self.loc = info['Directory']
self.version = info['Version']
+ self.idx = getidx(self)
for f in info['Files']:
if fnmatch(f['name'], '*.diff.gz'):
- self.diffgz=f
+ self.diffgz_name=f['name']
+ self.diffgz_size=f['size']
+ self.diffgz_md5sum=f['md5sum']
self.type = "Debian-diff"
- def idx(self):
- name = str(self)
- if len(name) < 4 or name[0:3] != "lib":
- return name[0]
- else:
- return name[0:4]
-
def __str__(self):
return self.name
+class MasterIndex:
+ def __init__(self):
+ self.pkgcounts = {}
+
+ def add(self, name):
+ idx = getidx(name)
+ if not self.pkgcounts.has_key(idx):
+ self.pkgcounts[idx] = 1
+ else:
+ self.pkgcounts[idx] += 1
+
+ def indices(self):
+ for k,v in sorted(self.pkgcounts.iteritems()):
+ yield (k,v)
+
class SourcePackageIndex:
def __init__(self):
self.pkgs = {}
def ins(self, srcpkg, rel):
- idx = srcpkg.idx()
- if not self.pkgs.has_key(idx):
- self.pkgs[idx] = {}
- if not self.pkgs[idx].has_key(srcpkg.name):
- self.pkgs[idx][srcpkg.name] = {}
- if not self.pkgs[idx][srcpkg.name].has_key(rel):
- self.pkgs[idx][srcpkg.name][rel] = srcpkg
+ if not self.pkgs.has_key(srcpkg.idx):
+ self.pkgs[srcpkg.idx] = {}
+ if not self.pkgs[srcpkg.idx].has_key(srcpkg.name):
+ self.pkgs[srcpkg.idx][srcpkg.name] = {}
+ if not self.pkgs[srcpkg.idx][srcpkg.name].has_key(rel):
+ self.pkgs[srcpkg.idx][srcpkg.name][rel] = srcpkg
+
+ def getletter(self, letter):
+ return self.pkgs[getidx(letter)]
def indices(self):
for k,v in sorted(self.pkgs.iteritems()):
diff --git a/patchtracker/Writers.py b/patchtracker/Writers.py
index 7e2fd1c..c3b59aa 100755
--- a/patchtracker/Writers.py
+++ b/patchtracker/Writers.py
@@ -23,8 +23,8 @@ class PackageVersTemplate(OurTemplate):
self.suite = suite
tpl=os.sep.join([Conf.template_dir, "package_vers.tmpl"])
sl = {}
- if srcpkg.diffgz:
- dfile = os.sep.join([Conf.archive_root,srcpkg.loc,srcpkg.diffgz['name']])
+ if srcpkg.diffgz_name:
+ dfile = os.sep.join([Conf.archive_root,srcpkg.loc,srcpkg.diffgz_name])
sl['diffhandler'] = DiffGzHandler(dfile)
else:
sl['diffhandler'] = None
@@ -34,20 +34,12 @@ class FrontPageTemplate(OurTemplate):
allindex = None
relindices = []
- def __init__(self, allindex, release_indices=[]):
+ def __init__(self, allindex):
tpl = os.sep.join([Conf.template_dir, "frontpage.tmpl"])
OurTemplate.__init__(self, file=tpl)
self.allindex = allindex
- self.relindices = release_indices
class LetterTocTemplate(OurTemplate):
- idx = None
- pkgs = None
- dists = None
-
- def releases(self):
- return dists
-
def __init__(self, letter, collection):
self.pkgs = collection
self.idx = letter
@@ -58,6 +50,9 @@ class LetterTocTemplate(OurTemplate):
tpl = os.sep.join([Conf.template_dir, "letter_toc.tmpl"])
OurTemplate.__init__(self, file=tpl)
+ def releases(self):
+ return dists
+
class ErrorTemplate(OurTemplate):
def __init__(self, msg):
tpl = os.sep.join([Conf.template_dir, "cgi_error.tmpl"])
@@ -97,9 +92,3 @@ class FrontPageWriter(PageWriter):
t = FrontPageTemplate(allindex, release_indices)
dest = os.sep.join([Conf.output_dir, "index.html"])
PageWriter.__init__(self, dest, t)
-
-class LetterTocWriter(PageWriter):
- def __init__(self, letter, collection):
- t = LetterTocTemplate(letter, collection)
- dest = os.sep.join([Conf.output_dir, "index", t.idx, "index.html"])
- PageWriter.__init__(self, dest, t)
diff --git a/templates/frontpage.tmpl b/templates/frontpage.tmpl
index e283f98..5cb7fcc 100644
--- a/templates/frontpage.tmpl
+++ b/templates/frontpage.tmpl
@@ -6,9 +6,13 @@ Debian Project patch tracking system
#def body
<h1>Debian Project patch tracking system</h1>
<h2>Browse patches by package name</h2>
-#for $k in $allindex.pkgs.iterkeys()
- #if $allindex.pkgs[$k]
- <a href="index/$k">$k</a>
- #end if
+ <table class="patchlisting">
+ <tr><th>index</th><th># packages</th></tr>
+#for $k,$v in $allindex.indices
+ <tr>
+ <td><a href="index/$k">$k</a></td>
+ <td>$v</td>
+ </tr>
#end for
+ </table>
#end def
diff --git a/templates/letter_toc.tmpl b/templates/letter_toc.tmpl
index 308e535..a5623f4 100644
--- a/templates/letter_toc.tmpl
+++ b/templates/letter_toc.tmpl
@@ -13,7 +13,7 @@ Debian Project patch tracking system
<th>$d</th>
#end for
</tr>
-#for $p in $pkgs
+#for $p in $sorted($pkgs.iterkeys)
<tr>
<td>
<a href="http://packages.debian.org/$p">$p</a>
diff --git a/templates/package_vers.tmpl b/templates/package_vers.tmpl
index 4ecd692..e1f6350 100755
--- a/templates/package_vers.tmpl
+++ b/templates/package_vers.tmpl
@@ -20,30 +20,30 @@ debian specific patch information for $src.name / $suite
<th>Source Package Format</th>
<td>$src.format</td>
</tr>
-#if $src.diffgz
+#if $src.diffgz_name
<tr>
<th>Diff.gz</th>
- <td>$src.loc / $src.diffgz['name']</td>
+ <td>$src.loc / $src.diffgz_name</td>
</tr>
#end if
</table>
-#if $src.diffgz
+#if $src.diffgz_name
<h2> "Debian diff" Information </h2>
<table class="patchlisting">
<tr>
<th>Diff file</th>
<td colspan="2">
- <a href="$conf.archive_root_url/$src.loc/$src.diffgz['name']">
- $src.diffgz['name']
+ <a href="$conf.archive_root_url/$src.loc/$src.diffgz_name">
+ $src.diffgz_name
</a>
</td>
</tr>
<tr>
- <th>Size</th><td colspan="2">$src.diffgz['size']</td>
+ <th>Size</th><td colspan="2">$src.diffgz_size</td>
</tr>
<tr>
- <th>MD5sum</th><td colspan="2">$src.diffgz['md5sum']</td>
+ <th>MD5sum</th><td colspan="2">$src.diffgz_md5sum</td>
</tr>
<tr>
<th>./debian only changes</th>
@@ -54,7 +54,7 @@ debian specific patch information for $src.name / $suite
<a href="$u/patch/debianonly/dl/$src.name/$src.version">download</a>
</td>
</tr>
-#if $src.diffgz and $diffhandler.nondebiandir.lines
+#if $src.diffgz_name and $diffhandler.nondebiandir.lines
<tr>
<th>non packaging (i.e. not ./debian) changes</th>
<td>
@@ -68,7 +68,7 @@ debian specific patch information for $src.name / $suite
</table>
#end if
-#if $src.diffgz and $diffhandler.nondebiandir.lines
+#if $src.diffgz_name and $diffhandler.nondebiandir.lines
<h2> Misc. Non-packaging "direct" style patches </h2>
<table class="patchlisting">
<tr>
@@ -81,7 +81,7 @@ debian specific patch information for $src.name / $suite
</table>
#end if
-#if $src.diffgz
+#if $src.diffgz_name
#set $series = $diffhandler.series
#if $series
<h2> "series" style patches </h2>