[Blends-commit] [SCM] website branch, master, updated. a80418c6c2cde5cafcbac2829a89b8b4f2667095

Andreas Tille tille at debian.org
Fri May 1 19:25:22 UTC 2015


The following commit has been merged in the master branch:
commit a80418c6c2cde5cafcbac2829a89b8b4f2667095
Author: Andreas Tille <tille at debian.org>
Date:   Thu Apr 30 17:06:48 2015 +0200

    Activate bugs_udd.py instead of bugs.py

diff --git a/webtools/blendstasktoolsold.py b/webtools/blendstasktoolsold.py
deleted file mode 100644
index 973ed18..0000000
--- a/webtools/blendstasktoolsold.py
+++ /dev/null
@@ -1,1686 +0,0 @@
-#!/usr/bin/python
-# Copyright 2008: Andreas Tille <tille at debian.org>
-# License: GPL
-
-# Blends metapackages are listing a set of Dependencies
-# These might be fullfilled by the Debian package
-# set or not.
-#
-# This interface provides some classes that contains
-# all available information about this Dependency ,
-# like whether it is an official package or not,
-# in which distribution it is contained
-# or if it is not contained it obtains information
-# from tasks file about home page, license, WNPP etc.
-
-#PORT=5441
-UDDPORT=5452
-PORT=UDDPORT
-DEFAULTPORT=5432
-
-from sys import stderr, exit
-from subprocess import Popen, PIPE
-import os
-import urllib
-import StringIO
-import gzip
-import bz2
-import re
-import email.Utils
-
-import psycopg2
-import gettext
-
-from genshi import Markup
-# ccording to http://genshi.edgewall.org/wiki/GenshiFaq#HowcanIincludeliteralXMLintemplateoutput
-# there are different options to prevent escaping '<' / '>' but HTML does not work ...
-# from genshi.input import HTML
-from blendsmarkdown import SplitDescription, MarkupString, render_longdesc
-
-from debian import deb822
-from blendsunicode import to_unicode
-
-import logging
-import logging.handlers
-logger = logging.getLogger('blends')
-logger.setLevel(logging.INFO)
-
-# Seems to have problems on 17.04.2009
-# BASEURL  = 'http://ftp.debian.org/debian'
-BASEURL  = 'http://ftp.de.debian.org/debian'
-# SVNHOST  = 'svn+ssh://svn.debian.org'
-SVNHOST  = 'svn://svn.debian.org'
-KEYSTOIGNORE = ( 'Architecture', 'Comment', 'Leaf', 'NeedConfig', 'Note', 'Section',
-                 'Needconfig', 'DontAvoid',
-                 'Enhances', 'Test-always-lang', 'Metapackage')
-# DDTP now exports to official debian mirror
-#DDTPURL = "http://ddtp.debian.net/debian/dists/"
-DDTPURL = "http://ftp.de.debian.org/debian/dists/"
-DDTPDIR = "/i18n/Translation-"
-DDTPLISTS = ('etch', 'lenny', 'sid')
-
-CONFDIR = 'webconf'
-
-COMPRESSIONEXTENSION='bz2'
-# COMPRESSIONEXTENSION='gz' # Translations are only available as bz2 since April 2009
-
-HOMEPAGENONE = '#'
-HOMEPAGENONEFIELDS = ('homepage', 
-                      'pkg-url',     # Link to packages.debian.org search interface with exact
-                                     # package matches or URL to inofficial package
-                      'vcs-browser', # Browser-URL to packaging stuff in Vcs
-                     )
-
-PKGURLMASK = 'http://packages.debian.org/search?keywords=%s%%26searchon=names%%26exact=1%%26suite=all%%26section=all'
-
-DEPENDENT  = 0
-SUGGESTED  = 1
-DONE       = 2
-BUGLISTCAT = (DEPENDENT, SUGGESTED, DONE )
-
-releases  = {'oldstable'    : ('etch', 'etch-proposed-updates', 'etch-security'),
-             'stable'       : ('lenny', 'lenny-proposed-updates', 'lenny-security'),
-             'testing'      : ('squeeze'),
-             'unstable'     : ('sid'),
-             'experimental' : ('experimental')
-            }
-
-pkgstatus = {'official_high' : # official package with high priority dependency
-                               { 'releases'     : ('oldstable', 'stable', 'testing', 'unstable'),
-                                 'components'   : ('main', ),
-                                 'dependencies' : ('Depends', 'Recommends'),
-                                 'fields-set'   : (),
-                                 'colorcode'    : 'Green: The project is <a href="#%s">available as an official Debian package and has high relevance</a>',
-                                 'order'        : 1
-                               },
-             'official_low'  : # official package with low priority dependency
-                               { 'releases'     : ('oldstable', 'stable', 'testing', 'unstable'),
-                                 'components'   : ('main', ),
-                                 'dependencies' : ('Suggests', ),
-                                 'fields-set'   : (),
-                                 'colorcode'    : 'Green: The project is <a href="#%s">available as an official Debian package but has lower relevance</a>',
-                                 'order'        : 2
-                               },
-             'non-free'      : # package in contrib or non-free, priority decreased to Suggests in any case
-                               { 'releases'     : ('oldstable', 'stable', 'testing', 'unstable'),
-                                 'component'    : ('contrib', 'non-free'),
-                                 'dependencies' : ('Depends', 'Recommends', 'Suggests'),
-                                 'fields-set'   : (),
-                                 'colorcode'    : 'Green: The project is <a href="#%s">available in Debian packaging pool but is not in Debian main</a>',
-                                 'order'        : 3
-                               },
-             'experimental'  : # package which exists only in experimental
-                               { 'releases'     : ('experimental', ),
-                                 'component'    : ('main', 'contrib', 'non-free'),
-                                 'dependencies' : ('Depends', 'Recommends', 'Suggests'),
-                                 'fields-set'   : (),
-                                 'colorcode'    : 'Yellow: The project is <a href="#%s">available in Debian packaging pool but is regarded as experimental</a>',
-                                 'order'        : 4
-                               },
-             'new'           : # package in new queue
-                               { 'releases'     : ('new', ),
-                                 'component'    : ('main', 'contrib', 'non-free'),
-                                 'dependencies' : ('Depends', 'Recommends', 'Suggests'),
-                                 'fields-set'   : (),
-                                 'colorcode'    : 'Yellow: A package of project is <a href="#%s">is in Debian New queue and hopefully available soon</a>',
-                                 'order'        : 5
-                               },
-             'pkgvcs'        : # Not yet packaged but packaging code in Vcs
-                               { 'releases'     : (),
-                                 'component'    : (),
-                                 'dependencies' : ('Depends', 'Recommends', 'Suggests'),
-                                 'fields-set'   : ('vcs-svn', 'vcs-git', 'vcs-browser'),
-                                 'colorcode'    : 'Yellow: The packaging of project is <a href="#%s">has started and a developer might try the packaging code in VCS or help packaging.</a>',
-                                 'order'        : 6
-                               },
-             'unofficial'    : # unofficial packages outside Debian
-                               { 'releases'     : (),
-                                 'component'    : (),
-                                 'dependencies' : ('Depends', 'Recommends', 'Suggests'),
-                                 'fields-set'   : ('pkg-url', ),
-                                 'colorcode'    : 'Yellow: There exists an <a href="#%s">unofficial package</a> of the project',
-                                 'order'        : 7
-                               },
-             'wnpp'          : # project which has at least a WNPP bug filed
-                               { 'releases'     : (),
-                                 'component'    : (),
-                                 'dependencies' : ('Depends', 'Recommends', 'Suggests'),
-                                 'fields-set'   : ('wnpp', ),
-                                 'colorcode'    : 'Red: The project is <a href="#%s">not (yet) available as a Debian package</a> but there is some record of interest (WNPP bug).',
-                                 'order'        : 8
-                               },
-             'prospective'   : # projects which might be interesting for a Blend but no work is done yet
-                               { 'releases'     : (),
-                                 'component'    : (),
-                                 'dependencies' : ('Depends', 'Recommends', 'Suggests'),
-                                 'fields-set'   : ('homepage', ),  # TODO: a description should be set as well ...
-                                 'colorcode'    : 'Red: The project is <a href="#%s">not (yet) available as a Debian package</a>.',
-                                 'order'        : 9
-                               },
-             'ignore'        : # Package inside Debian which is "under observation"
-                               { 'releases'     : (releases.keys()),
-                                 'component'    : ('main', 'contrib', 'non-free'),
-                                 'dependencies' : ('Ignore', ),
-                                 'fields-set'   : (),
-                                 'colorcode'    : '%s',
-                                 'order'        : 10
-                               },
-             'avoid'         : # Package inside Debian which should not go to a install medium of the Blend
-                               { 'releases'     : (releases.keys()),
-                                 'component'    : ('main', 'contrib', 'non-free'),
-                                 'dependencies' : ('Avoid', ),
-                                 'fields-set'   : (),
-                                 'colorcode'    : '%s',
-                                 'order'        : 11
-                               },
-             'unknown'       : # Everything else
-                               { 'releases'     : (),
-                                 'component'    : (),
-                                 'dependencies' : ('Depends', 'Recommends', 'Suggests'),
-                                 'fields-set'   : (),
-                                 'colorcode'    : 'White: The project has an %s status.',
-                                 'order'        : 100
-                               },
-             }
-
-# http://wiki.python.org/moin/HowTo/Sorting#Sortingbykeys
-_tmplist=[]
-for key in pkgstatus.keys():
-    _tmplist.append((key,pkgstatus[key]['order']))
-_tmpsorted = sorted(_tmplist, key=lambda x:(x[1], x[0]))
-pkgstatus_sortedkeys = []
-for _tmp in _tmpsorted:
-    pkgstatus_sortedkeys.append(_tmp[0])
-
-dep_strength_keys = []
-for pkgstat in pkgstatus:
-    for dep in pkgstatus[pkgstat]['dependencies']:
-        if dep not in dep_strength_keys:
-            dep_strength_keys.append(dep)
-
-license_in_component = {'main'     : 'DFSG free',
-                        'contrib'  : 'DFSG free, but needs non-free components',
-                        'non-free' : 'non-free'
-            }
-
-def GetDependencies2Use(dependencystatus=[], max_order='prospective'):
-    # Create a list of status of dependencies out of pkgstatus dictionary
-    use_dependencystatus = []
-    if dependencystatus == []:
-        for pkgstat in pkgstatus_sortedkeys:
-            # per default = if no expliczite dependencystatus are given, we are only interested in
-            # dependencies which are at least of order experimental
-            if pkgstatus[pkgstat]['order'] > pkgstatus[max_order]['order']:
-                continue
-            use_dependencystatus.append(pkgstat)
-    else:
-        # verify correctly given dependencies
-        for pkgstat in dependencystatus:
-            if pkgstat in pkgstatus.keys():
-                use_dependencystatus.append(pkgstat)
-            else:
-                logger.error("Unknown dependencystatus %s" % pkgstat)
-        if use_dependencystatus == []:
-            logger.error("No valid dependencystatus in", dependencystatus)
-    return use_dependencystatus
-
-###########################################################################################
-# Define several prepared statements to query UDD
-try:
-  conn = psycopg2.connect(host="localhost",port=PORT,user="guest",database="udd")
-except psycopg2.OperationalError, err:
-  logger.debug("PostgreSQL does not seem to run on port %i .. trying default port %i." % (PORT, DEFAULTPORT))
-  try:
-    conn = psycopg2.connect("service=udd")
-  except psycopg2.OperationalError, err:
-    # logger not known at this state: logger.warning
-    print >>stderr, "Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err))
-    try: 
-        conn = psycopg2.connect(host="localhost",port=DEFAULTPORT,user="guest",database="udd")
-    except psycopg2.OperationalError:
-        # Hmmm, I observed a really strange behaviour on one of my machines where connecting to
-        # localhost does not work but 127.0.0.1 works fine.  No idea why ... but this should
-        # do the trick for the moment
-        conn = psycopg2.connect(host="127.0.0.1",port=DEFAULTPORT,user="guest",database="udd")
-
-curs = conn.cursor()
-query = """PREPARE query_pkg (text) AS SELECT 
-                   distribution, component, version, architecture, maintainer,
-                   source, section, task, distribution, release, component, homepage,
-                   description FROM packages
-                   WHERE package = $1 ORDER BY version"""
-curs.execute(query)
-
-query = """PREPARE query_new (text) AS SELECT 
-                   distribution, component, version, architecture, maintainer,
-                   source, section, distribution, 'new' AS release, component, homepage,
-                   description, long_description FROM new_packages
-                   WHERE package = $1 ORDER BY version LIMIT 1"""
-curs.execute(query)
-
-# Sometimes the tasks file contains dependencies from virtual packages and we have to
-# obtain the real packages which provide this dependency.
-# First check whether there are such packages (only names)
-query = """PREPARE query_provides (text) AS 
-           SELECT package FROM packages WHERE provides = $1 GROUP BY package;"""
-curs.execute(query)
-
-# Obtain more detailed information about packages that might provide a dependency
-#query = """PREPARE query_provides_version_release (text) AS 
-#           SELECT package, version, release FROM packages WHERE provides = $1
-#                  GROUP BY version, package, release ORDER BY version DESC;"""
-#curs.execute(query)
-
-# Obtain the component a certain package might be in
-query = "PREPARE pkg_component (text) AS SELECT component FROM packages WHERE package = $1 GROUP BY component "
-curs.execute(query)
-
-# Obtain the releases featuring a certain package, in case a package might show up in different components when
-# considering different releases we apply a preference for main over contrib over non-free.  If this is the case
-# we mention only the releases of the selected component
-query = "PREPARE pkg_releases (text, text) AS SELECT release FROM packages WHERE package = $1 AND component = $2 GROUP BY release "
-curs.execute(query)
-
-# Obtain available versions including the architectures where this version is available
-#query = """PREPARE pkg_versions_arch (text, text) AS
-#   SELECT release, regexp_replace(version, '^[0-9]:', '') AS version, array_to_string(array_accum(architecture),',') AS architectures FROM
-#     ( SELECT architecture, version,
-#          release || CASE WHEN char_length(substring(distribution from '-.*')) > 0 THEN substring(distribution from '-.*') ELSE '' END AS release FROM packages
-#          WHERE package = $1 AND component = $2
-#          GROUP BY architecture, version, release, distribution
-#          ORDER BY architecture
-#     ) AS av
-#     GROUP BY version, release ORDER BY version DESC;"""
-query = """PREPARE pkg_versions_arch (text) AS
-   SELECT r as release, version, archs, component
-     FROM versions_archs_component($1) AS (r text, version text, archs text, component text)
-          -- you have to specify the column names because plain RECORD type is returned
-     JOIN releases ON releases.release = r
-          -- JOIN with release table to enable reasonable sorting
-    WHERE r NOT LIKE '%-%'
-          -- ignore releases like *-security etc.
-    ORDER BY releases.sort ASC, version DESC;"""
-curs.execute(query)
-
-query = """PREPARE pkg_versions_stable_testing (text) AS
-   SELECT release,  regexp_replace(regexp_replace(debversion, '-.*', ''), '[.+~]dfsg.*', '') AS version, debversion
-     FROM (SELECT r AS release, MAX(version) AS debversion
-             FROM versions_archs_component($1) AS (r text, version text, archs text, component text)
-            WHERE r IN ('lenny', 'squeeze') GROUP BY r) AS zw;"""  # Change here releases onace Squeeze is released
-curs.execute(query)
-
-# Obtain upstream version in case it is newer than Debian version
-query = """PREPARE pkg_dehs (text) AS
-   SELECT DISTINCT d.source, unstable_upstream, unstable_parsed_version, unstable_status, experimental_parsed_version, experimental_status FROM dehs d
-      JOIN  packages p ON p.source = d.source
-      WHERE p.package = $1 AND unstable_status = 'outdated' ;"""
-curs.execute(query)
-
-# Obtain Vcs Information from source table - use only latest version because this is 
-query = """PREPARE src_vcs (text) AS
-           SELECT vcs_type AS "vcs-type", vcs_url AS "vcs-url", vcs_browser AS "vcs-browser" FROM sources
-            WHERE source = $1 AND (vcs_type IS NOT NULL OR vcs_url IS NOT NULL OR vcs_browser IS NOT NULL)
-            ORDER BY version desc LIMIT 1"""
-curs.execute(query)
-
-# Obtain popcon data:
-#   inst     : number of people who installed this package;
-# * vote     : number of people who use this package regularly;
-#   old      : number of people who installed, but don't use this package regularly;
-# * recent   : number of people who upgraded this package recently;
-#   no-files : number of people whose entry didn't contain enough information (atime and ctime were 0).
-query = "PREPARE popcon (text) AS SELECT vote, recent FROM popcon WHERE package = $1"
-curs.execute(query)
-
-# Number of submissions
-query = "PREPARE popcon_submissions AS SELECT vote FROM popcon WHERE package = '_submissions'"
-curs.execute(query)
-
-# Debtags
-query = """PREPARE debtags (text) AS 
-            SELECT * FROM debtags WHERE
-                package = $1 AND
-                tag NOT LIKE 'implemented-in::%' AND
-                tag NOT LIKE 'protocol::%' AND
-                tag NOT LIKE '%::TODO' AND
-                tag NOT LIKE '%not-yet-tagged%';"""
-curs.execute(query)
-
-query = """PREPARE query_screenshots (text) AS
-           SELECT screenshot_url, large_image_url AS image, small_image_url AS icon, version
-                  FROM screenshots WHERE package = $1
-                  ORDER BY version DESC, image ;"""
-curs.execute(query)
-
-# This query might result in more packages than wanted, because when seeking for a
-# package 'foo'  it also matches an enhances field of 'bar, xfoo-xx, foo-doc, bazz'
-# and thus we get a false positive.  We have to preprocess the resultset by splitting
-# it into single packages and check again the whole word for matching.  This is
-# implemented below in Python
-######################################################################################
-# ATTENTION: Call this "EXECUTE query_check_enhances('%"+pkg+"%')"                   #
-#            I have no idea how to otherwise mask the '%' in the prepared statement. #
-######################################################################################
-query = """PREPARE query_check_enhances (text) AS
-            SELECT DISTINCT package, enhances FROM packages WHERE enhances LIKE $1"""
-curs.execute(query)
-
-# Obtain e-mail address of latest uploader of source package
-query = """PREPARE query_get_latest_uploader (text) AS
-           SELECT changed_by FROM upload_history WHERE source = $1 ORDER BY version DESC LIMIT 1;"""
-curs.execute(query)
-
-#########################################################################################
-
-def ReadConfig(blendname=''):
-    # Try to read config file CONFDIR/<blendname>.conf
-    conffile = CONFDIR + '/' + blendname + '.conf'
-    if not os.access(conffile, os.R_OK):
-        # if config file can not be found in local dir, try /etc/blends/webconf as fallback
-        conffile_default = '/etc/blends/webconf/' + blendname + '.conf'
-        if not os.access(conffile_default, os.R_OK):
-            logger.error("Unable to open config file %s or %s." % (conffile, conffile_default))
-            exit(-1)
-        conffile = conffile_default
-    f = open(conffile, 'r')
-    ret = { 'Blend'       : '',
-            'projectname' : '',
-            'projecturl'  : '',
-            'homepage'    : '',
-            'aliothurl'   : '',
-            'projectlist' : '',
-            'pkglist'     : '',
-            'logourl'     : '',
-            'css'         : '',
-            'outputdir'   : '',
-            'datadir'     : '',
-            'advertising' : None,  # headline with advertising string is optional
-          }
-    for stanza in deb822.Sources.iter_paragraphs(f, shared_storage=False):    
-        ret['Blend']       = stanza['blend']        # short name of the project
-        ret['projectname'] = stanza['projectname']  # Printed name of the project
-        ret['projecturl']  = stanza['projecturl']   # Link to the developer page with dynamic content
-                                                    # like for instance these tasks pages
-        ret['homepage']    = stanza['homepage']     # Homepage with general information about the project
-                                                    # for instance at www.debian.org or wiki.debian.org
-        ret['aliothurl']   = stanza['aliothurl']    # Link to the Alioth page of the project
-        ret['projectlist'] = stanza['projectlist']  # Mailinglist of the project
-        if stanza.has_key('pkglist'):
-    	    ret['pkglist'] = stanza['pkglist']      # Packaging Mailinglist = Maintainer of group maintained packages
-        if stanza.has_key('logourl'):
-            ret['logourl'] = stanza['logourl']      # URL to logo image (might be missing
-        ret['css']         = stanza['css']          # (relative) URL to CSS file
-        ret['outputdir']   = stanza['outputdir']    # Dir for storing output HTML files
-        ret['datadir']     = stanza['datadir']      # Dir for storing SVN information about project
-        ret['vcsdir']      = stanza['vcsdir']       # Path to Blend information files at svn.debian.org
-        if stanza.has_key('advertising'):
-            # we have to remove the gettext _() call which was inserted into the config
-            # file to enable easy input for config file editors - but the call has to
-            # be made explicitely in the python code
-            advertising = re.sub('_\(\W(.+)\W\)', '\\1', stanza['advertising'])
-            # gettext needs to escape '"' thus we need to remove the escape character '\'
-            ret['advertising'] = re.sub('\\\\"', '"', advertising)
-
-    return ret
-
-def FetchTasksFiles(data):
-    # Fetch tasks files from SVN of a Blend
-    # The specification of the repository containing the tasks files
-    # of a Blend can be done in webconf/<Blend>.conf
-
-    # tasks directory to obtain dependencies and debian/control to obtain meta
-    # information like the metapackage prefix
-    # Checkout/Update tasks from SVN
-    if data['vcsdir'].startswith('svn:'):
-        for dir in ('tasks', 'debian'):
-            tasksdir = data['datadir'] + '/' + dir
-            if not os.access(tasksdir, os.W_OK):
-                try:
-                    os.makedirs(tasksdir)
-                except:
-                    logger.error("Unable to create data directory", tasksdir)
-    	    svncommand = "svn %%s %s/%s %s >> /dev/null" % (data['vcsdir'], dir, tasksdir)
-    	    if os.path.isdir(tasksdir+'/.svn'):
-    	        svncommand = svncommand % ' --accept theirs-conflict up'
-            else:
-                os.system("mkdir -p %s" % (tasksdir))
-                svncommand = svncommand % 'co'
-            if os.system(svncommand):
-    	        logger.error("SVN command %s failed" % (svncommand))
-    	        if os.path.isdir(tasksdir+'/.svn'):
-    		    logger.error("Trying old files in %s ..." % tasksdir)
-    	        else:
-                    if os.listdir(tasksdir):
-                        logger.warning("No .svn directory found in %s but trying those random files there as tasks files." % tasksdir)
-                    else:
-                        logger.error("There are no old files in %s -> giving up" % tasksdir)
-                        exit(-1)
-    elif data['vcsdir'].startswith('git:') or data['vcsdir'].startswith('http:'):
-        githtml = data['vcsdir']
-#        if githtml.startswith('git:'):
-#            githtml=githtml.replace('git://','http://')
-    	if os.path.isdir(data['datadir']+'/.git'):
-	    gitcommand = "cd %s; git pull --quiet" % data['datadir']
-	else:
-	    gitcommand = "cd %s; git clone --quiet %s" % (re.sub('/[^/]+$', '', data['datadir']), githtml)
-        if os.system(gitcommand):
-    	    logger.error("Git command %s failed" % (gitcommand))
-    	    if os.path.isdir(data['datadir']+'/.git'):
-                logger.error("Trying old files in %s ..." % data['datadir'])
-    	    else:
-                if os.listdir(data['datadir']):
-                    logger.warning("No .git directory found in %s but trying those random files there as tasks files." % data['datadir'])
-                else:
-                    logger.error("There are no old files in %s -> giving up" % data['datadir'])
-                    exit(-1)
-    else:
-        logger.error("Don't know how to checkout tasks files from %s -> giving up" % data['vcsdir'])
-        exit(-1)
-    return data['datadir'] + '/tasks'
-
-def RowDictionaries(cursor):
-    """Return a list of dictionaries which specify the values by their column names"""
-
-    description = cursor.description
-    if not description:
-        # even if there are no data sets to return the description should contain the table structure.  If not something went
-        # wrong and we return NULL as to represent a problem
-        return NULL
-    if cursor.rowcount <= 0:
-        # if there are no rows in the cursor we return an empty list
-        return []
-
-    data = cursor.fetchall()
-    result = []
-
-    for row in data:
-        resultrow = {}
-        i = 0
-        for dd in description:
-            resultrow[dd[0]] = row[i]
-            i += 1
-        result.append(resultrow)
-    return result
-
-def BrowserFromVcsURL(vcs_type, vcs_url):
-    # Guess Vcs-Browser URL from VCS URL
-    if vcs_type.lower().startswith('svn'):
-        ret_url = re.sub('^svn:', 'http:', vcs_url)
-        ret_url = re.sub('/svn/', '/wsvn/', ret_url)
-        ret_url = re.sub('$', '?rev=0&sc=0', ret_url)
-    elif vcs_type.lower().startswith('git'):
-        ret_url = re.sub('^git:', 'http:', vcs_url)
-        ret_url = re.sub('/git/', '/?p=', ret_url)
-    elif vcs_type.lower().startswith('hg'):
-        # Seems that vcs_browser = vcs_url in Mercurial
-        return vcs_url
-    elif vcs_type.lower().startswith('bzr') or vcs_type.lower().startswith('cvs'):
-        logger.warning("No idea how to guess vcs_browser for %s URLS" % vcs_type)
-        return
-    else:
-        logger.warning("Unknown VCS for " + vcs_url)
-        return HOMEPAGENONE
-
-    if ret_url == vcs_url:
-        logger.warning("Unable to obtain Vcs-Browser from " + vcs_url)
-        return HOMEPAGENONE
-    return ret_url
-
-detect_vcs_cvs_re        = re.compile("://.*cvs")
-detect_vcs_svn_re        = re.compile("://.*svn")
-detect_vcs_git_re        = re.compile("://.*git")
-
-def VcsTypeFromBrowserURL(vcs_browser):
-    # Guess Vcs-Type from vcs_browser
-    if detect_vcs_cvs_re.search(vcs_browser):
-        return 'Cvs'
-    if detect_vcs_svn_re.search(vcs_browser):
-        return 'Svn'
-    if detect_vcs_git_re.search(vcs_browser):
-        return 'Git'
-    return 'Unknown VCS'
-
-# The following keys will be mostly used for programs that
-# are not yet existing in Debian and will go to our todo list
-PROPERTIES=('homepage', # Homepage of program
-            'section',  # Section of package in the Debian hierarchy
-            'source',   # Keep the source package name which is needed for ddpo subscription
-           )
-
-class DependantPackage:
-    # Hold information about a package that is in dependency list
-
-    def __init__(self, blendname=None, taskname=None):
-        self.blendname      = blendname # Blend that includes the package in dependency list
-        self.taskname       = taskname  # Task which includes the Dependency
-        self.pkg            = None # Name of dependant package
-        self.PrintedName    = None # Only for Meta package names - no use for a real dependant package
-                                   # FIXME -> object model
-        self.pkgstatus      = 'unknown' # global pkgstatus: characterizes status of dependency, release, packaging status
-        self.releases       = []   # List of releases a package might be in
-        self.component      = None # One of: 'main', 'contrib', 'non-free', if a package shows up in several components which
-                                   # might happen over different releases, just prefer main over contrib over non-free
-        self.why            = None # basically used as comment
-
-        self.properties     = {}
-        self.properties['license']     = 'unknown'
-        for field in HOMEPAGENONEFIELDS:
-            self.properties[field]    = HOMEPAGENONE
-        self.properties['Enhances'] = {} # Dictionary Enhancing pkg name as key, Link to package information as value; empty in most cases
-                                         # because Enhances relations are quite seldom
-        self.properties['stable_testing_version'] = [] # (release, version) tuples where release is codename for stable and testing
-        self.vcs_found      = 0    # we need a flag to store the fact whether Vcs information of a package is in UDD
-        self.version        = []   # list of {'release', 'version', 'archs'} dictionary containing version and architecture information
-        self.outdated       = {}   # If not empty directory then release='upstream' and package is outdated
-        self.popcon         = {}   # dictionary containing vote and recnt values of popcon information
-        self.popconsubmit   = 0    # number of popcon submissions - in case popcon import into UDD might be broken this remains 0
-        self.debtags        = []   # list of {'tag', 'value'} dictionary containing debtag information
-        self.screenshots    = []   # list of {'version', 'url'} dictionary containing screenshot information
-        self.icon           = None # URL of small screenshot icon
-        self.screenshot_url = None # URL to screenshots.debian.net
-        self.responsible    = None # E-Mail address of issuer of ITP or some person
-                                   # who volunteered to care for this program
-        self.filename       = None # Filename of package in the Debian pool
-        self.desc           = {}   # Prospective packages should have a description ...
-                                   # ... which could be copied to (or from if exists)
-                                   # WNPP bug and finally can be used for packaging
-        self.desc['en']     = {}   # An English description should be available in any case
-        self.experimental   = 0    # Set to 1 if package *only* in experimental but not in unstable/testing/stable
-        self.remark         = {}   # Optional remark for a package
-        self.dep_strength   = 0    # Type of Dependency (Depends, Recommends, Suggests, Experimental, New, Avoid, Ignore, WNPP
-
-    def _QueryUDD4Package(self, source):
-        # Query UDD for several properties of a package
-        query = "EXECUTE pkg_component ('%s')" % self.pkg
-        curs.execute(query)
-        if curs.rowcount == 0:
-            # the package does not exist in UDD table packages
-            # verify whether we have some information in NEW queue
-            query = "EXECUTE query_new ('%s')" % self.pkg
-            curs.execute(query)
-            if curs.rowcount == 0:
-                return
-
-            row = RowDictionaries(curs)[0]
-            self.component = row['component']
-            self.version   = [{'release':'new', 'version': row['version'], 'archs':row['architecture']} , ]
-            self.pkgstatus = 'new'
-            self.properties['pkg-url'] = 'http://ftp-master.debian.org/new/%s_%s.html' % (row['source'], row['version'])
-            for prop in PROPERTIES:
-                self.properties[prop] = row[prop]
-            self.desc['en']['short'] = MarkupString(to_unicode(row['description']), self.pkg, 'ShortDesc - New')
-            self.desc['en']['long']  = Markup(render_longdesc(row['long_description'].splitlines()))
-            (_name, _url) = email.Utils.parseaddr(row['maintainer'])
-            self.responsible = '<a href="mailto:%s">%s</a>' % (_url, to_unicode(_name))
-            logger.info("The package %s is not yet in Debian but it is just in the new queue. (Task %s)" % (self.pkg, self.taskname))
-
-            return
-        # = the package exists in UDD table packages
-        else:
-            # This might happen in cases where a package was in non-free and moved to main later or
-            # something like this.  If we find a certain package in more than one components we
-            # prefer main over contrib over non-free.
-            if curs.rowcount > 1:
-                in_main = 0
-                in_contrib = 0
-                for component in curs.fetchall():
-                    if component[0] == 'main':
-                        self.component = 'main'
-                        in_main       = 1
-                        break
-                    if component[0] == 'contrib':
-                        in_contrib    = 1
-                if in_main == 0:
-                    if in_contrib == 1:
-                        self.component = 'contrib'
-                    else:
-                        self.component = 'non-free'
-            else:
-                self.component = curs.fetchone()[0]
-        # Debian Edu contains packages from main/debian-installer
-        if self.component == 'main/debian-installer':
-                self.component = 'main'
-        self.properties['license'] = license_in_component[self.component]
-
-        query = "EXECUTE pkg_releases ('%s', '%s')" % (self.pkg, self.component)
-        curs.execute(query)
-        has_official = 0
-        for rel in curs.fetchall():
-            self.releases.append(rel[0])
-            if rel[0] != 'experimental':
-                has_official = 1
-
-        # query = "EXECUTE pkg_versions_arch ('%s', '%s')" % (self.pkg, self.component)
-        query = "EXECUTE pkg_versions_arch ('%s')" % (self.pkg)
-        curs.execute(query)
-        if curs.rowcount > 0:
-            for row in RowDictionaries(curs):
-                if self.component.startswith(row['component']):
-                    self.version.append({'release':row['release'], 'version': row['version'], 'archs':row['archs']})
-                else:
-                    self.version.append({'release':row['release'], 'version': row['version'] + ' (' + row['component'] + ')', 'archs':row['archs']})
-
-        # Version in stable / testing for long table
-        query = "EXECUTE pkg_versions_stable_testing ('%s')" % (self.pkg)
-        curs.execute(query)
-        if curs.rowcount > 0:
-            prefix = 'Versions: '
-            for row in RowDictionaries(curs):
-                self.properties['stable_testing_version'].append((row['release'], row['debversion'], row['version'], prefix))
-                prefix = ', '
-
-        query = "EXECUTE pkg_dehs ('%s')" % (self.pkg)
-        curs.execute(query)
-        if curs.rowcount > 0:
-            row = RowDictionaries(curs)[0]
-            # it might be that the new upstream goes to experimental - this should be ignored here
-            if row['experimental_status'] != 'uptodate':
-                self.outdated['release']       = 'upstream'
-                self.outdated['version']       = row['unstable_upstream']
-                self.outdated['architectures'] = ''
-
-        query = "EXECUTE popcon ('%s')" % (self.pkg)
-        curs.execute(query)
-        if curs.rowcount > 0:
-            row = RowDictionaries(curs)[0]
-            self.popcon['vote']   = row['vote']
-            self.popcon['recent'] = row['recent']
-
-        query = "EXECUTE debtags ('%s')" % (self.pkg)
-        curs.execute(query)
-        if curs.rowcount > 0:
-            tagdict = {}
-            taglist = []
-            for row in RowDictionaries(curs):
-                (tag,value) = row['tag'].split('::')
-                if tagdict.has_key(tag):
-                    tagdict[tag] += ', ' + value
-                else:
-                    tagdict[tag]  = value
-                    taglist.append(tag)
-            if taglist:
-                taglist.sort()
-                for tag in taglist:
-                    self.debtags.append({'tag':tag, 'value':tagdict[tag]})
-
-        query = "EXECUTE query_screenshots ('%s')" % (self.pkg)
-        curs.execute(query)
-        if curs.rowcount > 0:
-            rows = RowDictionaries(curs)
-            self.icon           = rows[0]['icon']
-            self.image          = rows[0]['image']
-            self.screenshot_url = rows[0]['screenshot_url']
-            # if a package has more than one screenshots provide a list of these
-            if curs.rowcount > 1:
-                for row in rows:
-                    self.screenshots.append({'version':row['version'], 'url':row['image']})
-
-        if has_official == 1:
-            if self.component == 'main':
-                if self.dep_strength == 'Depends' or self.dep_strength == 'Recommends':
-                    self.pkgstatus = 'official_high'
-                else:
-                    self.pkgstatus = 'official_low'
-            else:
-                    self.pkgstatus = 'non-free'
-        else:
-            self.pkgstatus = 'experimental'
-
-        # link to packages.debian.org search page to see overview about all
-        # package versions in all releases
-        self.properties['pkg-url'] = PKGURLMASK % self.pkg
-
-        query = "EXECUTE query_pkg ('%s')" % self.pkg
-        curs.execute(query)
-
-        for row in RowDictionaries(curs):
-            for prop in PROPERTIES:
-                self.properties[prop] = row[prop]
-            self.desc['en']['short'] = MarkupString(to_unicode(row['description']), self.pkg, 'ShortDesc')
-            self.desc['en']['long']  = 'unused'
-            (_name, _url) = email.Utils.parseaddr(row['maintainer'])
-            self.properties['maintainer'] = to_unicode(row['maintainer'])
-            self.responsible = '<a href="mailto:%s">%s</a>' % (_url, to_unicode(_name))
-
-        if self.properties.has_key('source'):
-            query = "EXECUTE src_vcs ('%s')" % (self.properties['source'])
-            curs.execute(query)
-            if curs.rowcount > 0:
-                # There is only one line returned by this query
-                row = RowDictionaries(curs)[0]
-                # If some information about Vcs is found in the database make sure it is ignored from tasks file
-                self.vcs_found = 1
-                for prop in row.keys():
-                    if row[prop]:
-                        self.properties[prop] = row[prop]
-                if not self.properties.has_key('vcs-browser') or self.properties['vcs-browser'] == HOMEPAGENONE:
-                    try:
-                        self.properties['vcs-browser'] = BrowserFromVcsURL(self.properties['vcs-type'], self.properties['vcs-url'])
-                    except KeyError, err:
-                        logger.warning("Vcs Property missing in Database:", self.properties, err)
-                if not self.properties.has_key('vcs-type') or not self.properties['vcs-type']:
-                    if self.properties.has_key('vcs-browser') and self.properties['vcs-browser'] != HOMEPAGENONE:
-                        self.properties['vcs-type']    = VcsTypeFromBrowserURL(self.properties['vcs-browser'])
-            # We are only interested in source packages (for instance for Bugs page)
-            if source == 1:
-                self.pkg = self.properties['source']
-            # Stop using source package in self.pkg because we need the source package to obtain latest uploaders and
-            # and bugs should be rendered in the same job - so we need the differentiation anyway
-            self.src = self.properties['source']
-        else:
-            logger.error("Failed to obtain source for package", self.pkg)
-            return
-
-        query = "EXECUTE query_get_latest_uploader ('%s')" % (self.src)
-        curs.execute(query)
-        try:
-            changed = to_unicode(curs.fetchone()[0])
-	except TypeError, err:
-            changed = None
-            logger.info("Query '%s' does not result in a valid changed entry (%s)" % (query, err))
-        if changed:
-            # self.properties['maintainer'] = to_unicode(self.properties['maintainer']) # .encode('utf-8')
-            try:
-                if not changed.startswith(self.properties['maintainer']):
-                    (_name, _url) = email.Utils.parseaddr(changed)
-                    changed = '<a href="mailto:%s">%s</a>' % (_url, _name)
-                    self.properties['changed_by']    = MarkupString(changed, self.pkg, 'changed_by')
-                    self.properties['last_uploader'] = to_unicode(changed)
-                    self.properties['last_uploader_simple'] = to_unicode('%s <%s>' % (_name, _url))
-            except UnicodeDecodeError, err:
-                logger.error("Failed to compare changed with maintainer - assume both are the same for package %s (%s)", self.pkg, err)
-
-        query = "EXECUTE query_check_enhances ('%"+self.pkg+"%')"
-        curs.execute(query)
-
-        if curs.rowcount > 0:
-            for row in RowDictionaries(curs):
-                enhancelist = row['enhances'].split(', ')
-                if self.pkg in enhancelist:
-                    if not row['package'] in self.properties['Enhances'].keys():
-                        self.properties['Enhances'][row['package']] = PKGURLMASK % row['package']
-            # if self.properties['Enhances'] != {}:
-            #    print "The following packages are enhancing %s: " % self.pkg,
-            #    for enh in self.properties['Enhances'].keys():
-            #        print enh,
-            #    print
-
-    # sort these objects according to the package name
-    def __cmp__(self, other):
-        # Comparing with None object has to return something reasonable
-        if other == None:
-            return -2
-        # Sort according to package name
-        return cmp(self.pkg, other.pkg)
-
-    def __str__(self):
-        ret = "Blend: " + self.blendname + ", " \
-              "Task:"   + self.taskname  + ", " \
-              "pkg:"    + self.pkg
-        if self.dep_strength:
-            ret += ", Dep_strength: " + self.dep_strength
-        if self.pkgstatus:
-            ret += ", Pkg_status: "   + str(self.pkgstatus)
-        if self.releases:
-            ret += ", releases: "     + str(self.releases)
-        if self.component:
-            ret += ", component: "    + self.component
-        if self.version:
-            ret += ", versions: "     + str(self.version)
-        if self.desc:
-            ret += ", desc: "         + str(self.desc)
-        for prop in self.properties.keys():
-            ret += ", %s: %s" % (prop, str(self.properties[prop]))
-        # if self.desc['en']:
-        #    ret += ", desc['en']:"   + str(self.desc['en'])
-        return ret
-
-
-class Tasks:
-    # Provide a list of depencencies defined in metapackages
-    # This class concerns _all_ tasks of a Blend and is the most
-    # complete source of information.  If only a single task
-    # should be handled by a tool that uses blendtasktools
-    # probably the class TaskDependencies (see below) is
-    # your friend
-
-    def __init__(self, blendname):
-
-        os.system("mkdir -p logs")
-        LOG_FILENAME = 'logs/'+blendname+'.log'
-        handler = logging.handlers.RotatingFileHandler(filename=LOG_FILENAME,mode='w')
-        formatter = logging.Formatter("%(levelname)s - %(filename)s (%(lineno)d): %(message)s")
-        handler.setFormatter(formatter)
-        logger.addHandler(handler)
-
-        # This Instance of the Available class contains all
-        # information about packages that are avialable in Debian
-        # See below for more information about Available class
-        self.data            = ReadConfig(blendname)
-        self.blendname       = self.data['Blend']
-        self.tasksdir        = FetchTasksFiles(self.data)
-        self._InitMetapackages()
-        self.tasks           = {} # Dictionary of TasksDependency objects
-        self.alldeps_in_main = [] # sorted string list of package names with all packages
-                                  # relevant for a Blend that are in main Debian (for use in DDTP)
-        self.alldeps_in_main_info = {} # complete dictionary with package information
-                                  # with all packages relevant for a Blend that are in
-                                  # main to easily feed DDTP translation into the structures
-                                  # -->
-                                  # self.alldeps_in_main = self.alldeps_in_main_info.keys().sort()
-
-    def _InitMetapackages(self):
-        # sorted list of metapackage names
-        self.metapackagekeys = []
-        for task in os.listdir(self.tasksdir):
-            if os.path.isfile("%s/%s" % (self.tasksdir, task)):
-                self.metapackagekeys.append(task)
-        self.metapackagekeys.sort()
-
-    def GetAllDependencies(self, source=0):
-        # If we want to subscribe ddpo we need the source package names.
-        # In this case set source=1
-
-        if self.metapackagekeys == []:
-            self._GetMetapackages()
-
-        # Obtain the prefix of the meta packages of the Blend using blends-dev tools blend_get_names
-        if os.access('/usr/share/blends-dev/blend-get-names', os.X_OK):
-            blend_get_names = '/usr/share/blends-dev/blend-get-names'
-        elif os.access(os.getcwd() + '/blend-get-names', os.X_OK):
-            blend_get_names = os.getcwd() + '/blend-get-names'
-        else:
-            logger.critical("Please either install package Blends-dev or install a copy of devtools/blend-get-names in your working directory")
-            exit(-1)
-
-        # The prefix is used to build the meta package name that belongs to the task
-        cmd = "cd %s; %s metapackageprefix" % (self.data['datadir'], blend_get_names)
-        pipe = Popen(cmd, shell=True, stdout=PIPE).stdout
-        prefix = pipe.read().strip() + '-'
-        pipe.close()
-        for task in self.metapackagekeys:
-            td = TaskDependencies(self.blendname, task=task, tasksdir=self.tasksdir, prefix=prefix)
-            td.GetTaskDependencies(source)
-            self.tasks[task] = td
-
-        if source == 0:
-            # overall popcon submissions
-            query = "EXECUTE popcon_submissions"
-            curs.execute(query)
-            if curs.rowcount > 0:
-                self.popconsubmit = curs.fetchone()[0]
-            self.LinkEnhances()
-
-    def GetNamesOnlyDict(self, dependencystatus=[]):
-        # David Paleino needs for his web tools a dictionary
-        # { taskname : [list of dependencies]}
-        # This will be prepared here from the main
-        # datastructure
-        ret = {}
-        use_dependencystatus = GetDependencies2Use(dependencystatus, 'experimental')
-             
-        for task in self.metapackagekeys:
-            tdeps = self.tasks[task]
-            list = []
-            for dep in use_dependencystatus:
-                for tdep in tdeps.dependencies[dep]:
-                    list.append(tdep.pkg)
-            ret[task] = list
-        return ret
-
-    def GetUpdatablePackages(self, dependencystatus=[]):
-        # List of Updatable packages: sourcepkg, version, upstream version
-        ret = {}
-        use_dependencystatus = GetDependencies2Use(dependencystatus, 'experimental')
-
-        for task in self.metapackagekeys:
-            tdeps = self.tasks[task]
-            list = []
-            for dep in use_dependencystatus:
-                for tdep in tdeps.dependencies[dep]:
-            	    if tdep.outdated != {}:
-                        if tdep.properties.has_key('last_uploader_simple'):
-                            last_uploader = tdep.properties['last_uploader_simple']
-                        else:
-                            last_uploader = None
-            		# versions are ordered lists      ---v--- last one is needed
-                	list.append(((tdep.pkg, tdep.version[-1]['version'], tdep.outdated['version'], tdep.properties['maintainer']), last_uploader))
-            if list:
-        	ret[task] = list
-        return ret
-
-    def GetNamesAndSourceDict(self, dependencystatus=()):
-        # For the bugs pages we need not only the binary package names but the
-        # source package as well to be able to link to the QA page
-        # The lists are tripels with first value package name and the second source name
-        # The last value characterises the strength of dependency: Possible values
-        # are 'suggested' for Suggested packages, and 
-        ret = {}
-        if dependencystatus == ():
-            # see above in GetNamesOnlyDict() ... but when we are looking for bugs a
-            # reasonable default is to use only official dependencystatus
-            dependencystatus=('official_high', 'official_low', 'non-free', 'experimental')
-
-        for task in self.metapackagekeys:
-            tdeps = self.tasks[task]
-            list = []
-            for dep in dependencystatus:
-                if dep != 'official_high':
-                    bugrelevantdependency = SUGGESTED
-                else:
-                    bugrelevantdependency = DEPENDENT
-                for tdep in tdeps.dependencies[dep]:
-                    bugreldep = bugrelevantdependency
-                    # packages outside main can not be Depends but only Suggests
-                    if bugreldep == DEPENDENT and tdep.component != 'main':
-                        bugreldep = SUGGESTED
-                    list.append( { 'pkgname'              : tdep.pkg,
-                                   'source'               : tdep.properties['source'],
-                                   'homepage'             : tdep.properties['homepage'],
-                                   'vcs-browser'          : tdep.properties['vcs-browser'],
-                                   'maintainer'           : tdep.responsible,
-                                   'bugrelevantdependency': bugreldep
-                                   } )
-            ret[task] = list
-        return ret
-
-    def GetTaskDescDict(self):
-        # Return dictionary with description information of all tasks of a Blend
-        return self.tasks
-
-    def GetAllDependentPackagesOfBlend(self, dependencystatus=[]):
-        # David Paleino needs for his DDTP web tool a list of
-        # all available Dependencies.
-        # Here only those packages are returned that are in
-        # Debian main, because there are no DDTP translations
-        # for contrib and non-free available
-        if self.alldeps_in_main != []:
-            return self.alldeps_in_main
-
-        use_dependencystatus = GetDependencies2Use(dependencystatus, 'unknown')
-        for task in self.metapackagekeys:
-            tdeps = self.tasks[task]
-            for dep in use_dependencystatus:
-                for tdep in tdeps.dependencies[dep]:
-                    # add only packages in main, because others do not have DDTP translations
-                    if tdep.component == 'main':
-                        self.alldeps_in_main.append(tdep.pkg)
-                        self.alldeps_in_main_info[tdep.pkg] = tdep
-            # Also add meta package itself to make use of translated meta package description
-            self.alldeps_in_main.append(self.tasks[task].metapkg.pkg)
-            self.alldeps_in_main_info[self.tasks[task].metapkg.pkg] = self.tasks[task].metapkg
-        self.alldeps_in_main.sort()
-        return self.alldeps_in_main
-
-    def MarkupPreformatedStringsBlend(self):
-        # Genshi does not touch strings that are marked with "Markup()" - so just
-        # mark the strings that are ready formatted for the whole Blend
-        for task in self.metapackagekeys:
-            tdeps = self.tasks[task]
-            tdeps.MarkupPreformatedStrings()
-
-    def CheckOrCreateOutputDir(self, subdir):
-        outputdir = self.data['outputdir'] + '/' + subdir
-        if not os.access(outputdir, os.W_OK):
-            try:
-		os.mkdir(outputdir)
-            except:
-		# if more than one dir in the tree has to be crated just use mkdir -p ...
-		try:
-			os.system("mkdir -p %s" % outputdir)
-		except:
-			logger.error("Unable to create output dir " + outputdir)
-			return None
-        return outputdir
-
-    def LinkEnhances(self):
-        # To provide a connection between packages enhancing other packages a set of links
-        # will be provided.  The links should point to paragraphs on the tasks pages if the
-        # Enhancing package is listed in the metapackages of the blend and to packages.debian.org
-        # otherwise
-        for task in self.metapackagekeys:
-            tdeps = self.tasks[task]
-            for dependency in tdeps.dependencies.keys():
-                for dep in tdeps.dependencies[dependency]:
-                    if dep.properties['Enhances'] != {}:
-                        logger.debug("Package %s is enhanced by:" % dep.pkg)
-                        for enh in dep.properties['Enhances'].keys():
-                            # seek for Enhances on same page
-                            found = 0
-                            for seek_dependency in tdeps.dependencies.keys():
-                                for enhdep in tdeps.dependencies[seek_dependency]:
-                                    if enh == enhdep.pkg:
-                                        dep.properties['Enhances'][enh] = '#'+enh
-                                        found = 1 # found enhances in same task
-                                        break
-                            if found == 0: # If not found seek in other tasks
-                                for enhtask in self.metapackagekeys:
-                                    if enhtask == task:
-                                        continue
-                                    enhtdeps = self.tasks[enhtask]
-                                    for seek_dependency in enhtdeps.dependencies.keys():
-                                        for enhdep in enhtdeps.dependencies[seek_dependency]:
-                                            if enh == enhdep.pkg:
-                                                dep.properties['Enhances'][enh] = './' + enhtask + '#' + enh
-                                                found = 1 # found enhances in other task
-                                                break
-                                    if found == 1:
-                                        break
-                            logger.debug(" %s -> %s" % (enh, dep.properties['Enhances'][enh]))
-
-    def __str__(self):
-        ret = "Blendname: "       + self.blendname  + ", " \
-              "Metapackagekeys: " + str(self.metapackagekeys) + ", "
-        tab = "\nTasks: "
-        for task in self.metapackagekeys:
-            ret += tab
-            semikolon = ''
-            for pstatus in self.tasks[task].dependencies.keys():
-                if self.tasks[task].dependencies[pstatus] == []:
-                    continue
-                ret += semikolon + pstatus + ': ['
-                semikolon = '; '
-                komma = ''
-                for dep in self.tasks[task].dependencies[pstatus]:
-                    ret += komma + dep.pkg
-                    komma = ', '
-                ret += ']'
-            tab  = "\n       "
-        ret = ret + "\n" \
-              "All deps in main:" + str(self.alldeps_in_main) + ",\n" \
-              "All deps in main Info:" + str(self.alldeps_in_main_info)
-
-        return ret
-
-class TaskDependencies:
-    # List of depencencies defined in one metapackage
-    def __init__(self, blendname, task, tasksdir=None, prefix=''):
-
-        self.data     = ReadConfig(blendname)
-        self.blendname  = self.data['Blend']
-        if tasksdir != None:
-            self.tasksdir = tasksdir
-        else:
-            self.tasksdir = InitTasksFiles(self.data)
-        self.taskfile = self.tasksdir+'/'+task
-        if os.path.isfile(self.taskfile):
-            self.task = task
-        else:
-            logger.error("No such task file %s." % self.taskfile)
-            return None
-
-        # Dictionary with satus of dependencies as key and list of DependantPackage
-        # instances
-        self.dependencies = {}
-        for pkgstat in pkgstatus:
-            self.dependencies[pkgstat] = []
-
-        # Main information for a task
-        self.metapkg             = DependantPackage(self.blendname, self.task)
-        self.metapkg.pkg         = prefix + task
-
-        # If a Blend just bases on the meta package of an other Blend (this is the
-        # case in Debian Science which bases on med-bio for biology and gis-workstation
-        # for geography it makes no sense to build an own sentinel page but read
-        # meta package information of other meta packages and include the content
-        # of these while enabling to add further Dependencies as well
-        #
-        # metadepends should be a SVN URL
-        #
-        # This is NOT YET implemented
-        self.metadepends     = None
-
-    def _AppendDependency2List(self, dep, source):
-        # Append dependency which was found in the tasks file if not Ignore / Avoid and
-        # no dupplication in case of source depencencies
-        if dep == None:
-            return
-        if dep.dep_strength == 'Ignore' or dep.dep_strength == 'Avoid':
-            return
-        if source != 1:
-            # In general we can just add the dependency to the list
-            self.dependencies[dep.pkgstatus].append(dep)
-            return
-
-        # if we are seeking for ddpo source packages we have to make sure that
-        # no duplication occures
-        hasnot = 1
-        for hasdep in self.dependencies[dep.pkgstatus]:
-            if hasdep.pkg == dep.pkg:
-                hasnot = 0
-                break
-        if hasnot == 1:
-            self.dependencies[dep.pkgstatus].append(dep)
-
-    def GetTaskDependencies(self, source=0):
-        global dep_strength_keys
-
-        f = file(self.taskfile)
-        for stanza in deb822.Sources.iter_paragraphs(f):
-            # Why and Responsible can be valid for more than one dependency
-            # Store them in strings and use them for all Dependent Package objects
-            why               = None
-            responsible       = None
-            dep               = None
-            remark            = {}
-            tmp_dep_list      = []
-            fields_duplicated = None
-            fields_obsolete   = []
-            for key in stanza:
-                if key == 'Task':
-                    # also the task name might be utf-8 encoded
-                    self.metapkg.PrintedName = to_unicode(stanza['task'])
-                    continue
-                if key == 'Description':
-                    (short, long) = SplitDescription(stanza['description'])
-                    # Markup strings to enable verbatim output of preformatted text
-                    self.metapkg.desc['en']['short'] = MarkupString(short.encode('utf-8'), self.metapkg.PrintedName, 'taskShortDesc')
-                    self.metapkg.desc['en']['long']  = MarkupString(long.encode('utf-8'),  self.metapkg.PrintedName, 'taskLongDesc')
-
-                    # find maintainer and other metadata:
-                    query = "EXECUTE query_pkg ('%s')" % self.metapkg.pkg
-                    curs.execute(query)
-                    if curs.rowcount > 0:
-                        row = RowDictionaries(curs)[0]
-                        (_name, _url) = email.Utils.parseaddr(row['maintainer'])
-                        self.responsible = '<a href="mailto:%s">%s</a>' % (_url, to_unicode(_name))
-
-                    continue
-                if key == 'Meta-Depends':
-                    self.metadepends = stanza['meta-depends']
-                if key == 'Meta-Suggests':
-                    self.metadepends = stanza['meta-suggests']
-                if key == 'Why':
-                    why = stanza['why']
-                    continue
-                if key == 'Responsible':
-                    responsible = stanza['responsible'].strip()
-            	    if not dep:
-            		# Make sure there is really enough information to deal with provided by the package
-            		logger.error("Missing package information for field %s = %s" % (key, responsible))
-            		continue
-                    if dep.responsible != None:
-                        # we are dealing with an official package that has a real maintainer who
-                        # is finally responsible
-                        # ... but do not issue a hint about this in the logs. Sometimes a responsible
-                        # person makes sense in the tasks field
-                        # fields_obsolete.append(key)
-                        continue
-                    if responsible != '':
-                        (_name, _url) = email.Utils.parseaddr(responsible)
-                        dep.responsible = '<a href="mailto:%s">%s</a>' % (_url, to_unicode(_name))
-                    continue
-
-                if key in dep_strength_keys:
-                    # Hack: Debian Edu tasks files are using '\' at EOL which is broken
-                    #       in RFC 822 files, but blend-gen-control from blends-dev relies
-                    #       on this.  So remove this stuff here for the Moment
-                    dependencies = re.sub('\\\\\n\s+', '', stanza[key])
-
-                    # Remove versions from versioned depends
-                    dependencies = re.sub(' *\([ ><=\.0-9]+\) *', '', dependencies)
-
-                    # turn alternatives ('|') into real depends for this purpose
-                    # because we are finally interested in all alternatives
-                    dependencylist = dependencies.replace('|',',').split(',')
-                    # Collect all dependencies in one line first,
-                    # create an object for each later
-                    deps_in_one_line = []
-                    for dependency in dependencylist:
-                        if dependency.strip() != '': # avoid confusion when ',' is at end of line
-                            deps_in_one_line.append(dependency.strip())
-
-                    for dep_in_line in deps_in_one_line:
-                        # If there are more than one dependencies in one line
-                        # just put the current one into the right list of dependencies
-                        # before initiating the next instance
-                        if dep != None:
-                            tmp_dep_list.append(dep)
-                        dep = DependantPackage(self.blendname, self.task)
-                        # Store the comments in case they might be usefull for later applications
-                        dep.why            = why
-                        dep.responsible    = responsible
-                        dep.dep_strength   = key
-                        if dep_in_line.islower():
-                            dep.pkg            = dep_in_line
-                        else:
-                            dep.pkg            = dep_in_line.lower()
-                            logger.warning("Package names may not contain upper case letters, so %s is an invalid package name which is turned into %s" \
-                                % (dep_in_line, dep.pkg))
-
-                        dep._QueryUDD4Package(source)
-
-                    continue
-
-                # sometimes the tasks file contains standalone comments or other RFC 822 entries.
-                # Just ignore this stuff
-                if dep == None:
-                    continue # ... with next stanza
-
-                # the following fields might be provided in the Blends tasks file for
-                # prospective packages.  This information should be ignored in case the
-                # package just exists at Debian mirrors
-                if pkgstatus[dep.pkgstatus]['order'] <= pkgstatus['experimental']['order']:
-                    # for packages not in Debian we use the information from the tasks file
-                    # if a package is in Debian we use the information from the Packages file (via UDD query)
-                    # and the fields may not be overriden.  The list collects duplicated fields and will
-                    # trigger a warning if the list is not empty
-                    # TODO: warn about possibly duplicated prospective package entries in tasks files
-                    fields_duplicated = []
-
-                # The following keys will be mostly used for programs that
-                # are not yet existing in Debian and will go to our todo list
-                if key == 'Homepage':
-                    if fields_duplicated != None:
-                        fields_duplicated.append(key)
-                    if dep != None:
-                        # set Homepage only if not just set via official package information
-                        if dep.properties['homepage'] == HOMEPAGENONE:
-                            dep.properties['homepage'] = to_unicode(stanza['homepage'])
-                        else:
-                            fields_obsolete.append(key)
-                    else:
-                        logger.error("Dep not initiated before Homepage %s -> something is wrong." \
-                              % stanza['homepage'])
-                elif key == 'Vcs-Svn' or key == 'vcs-svn': # strangely enough on alioth the later
-                                                           # spelling seems to be needed - no idea why
-                    if dep != None:
-                        if dep.vcs_found == 1:
-                            fields_obsolete.append(key)
-                            continue
-                        dep.properties['vcs-url']  = stanza['vcs-svn']
-                        dep.properties['vcs-type'] = 'SVN'
-                        # if Vcs-Svn is given we are able to obtain the Browser URL of wsvn
-                        if dep.properties['vcs-browser'] == HOMEPAGENONE:
-                            try:
-                                dep.properties['vcs-browser'] = BrowserFromVcsURL(dep.properties['vcs-type'], dep.properties['vcs-url'])
-                            except KeyError, err:
-                                logger.error("Vcs Property missing in packages file:", dep.properties, err)
-                    else:
-                        logger.error("Dep not initiated before Vcs-Svn %s -> something is wrong." \
-                              % stanza['vcs-svn'])
-                    if dep.pkgstatus == 'unknown':
-                        dep.pkgstatus = 'pkgvcs'
-                elif key == 'Vcs-Git' or key == 'vcs-git': # strangely enough on alioth the later
-                                                           # spelling seems to be needed - no idea why
-                    if dep != None:
-                        if dep.vcs_found == 1:
-                            fields_obsolete.append(key)
-                            continue
-                        dep.properties['vcs-url']  = stanza['vcs-git']
-                        dep.properties['vcs-type'] = 'Git'
-                        # if Vcs-Git is given we are able to obtain the Browser URL of wsvn
-                        if dep.properties['vcs-browser'] == HOMEPAGENONE:
-                            dep.properties['vcs-browser'] = BrowserFromVcsURL(dep.properties['vcs-type'], dep.properties['vcs-url'])
-                    else:
-                        logger.error("Dep not initiated before Vcs-Git %s -> something is wrong." \
-                              % stanza['vcs-git'])
-                elif key == 'Vcs-Browser' or key == 'vcs-browser': # strangely enough on alioth the later
-                                                           # spelling seems to be needed - no idea why
-                    if dep != None:
-                        if dep.vcs_found == 1:
-                            fields_obsolete.append(key)
-                            continue
-                        dep.properties['vcs-browser'] = stanza['vcs-browser']
-                        if re.compile("[/.]git\.").search(dep.properties['vcs-browser']):
-                    	    dep.properties['vcs-type'] = 'Git'
-                        elif re.compile("[/.]svn\.").search(dep.properties['vcs-browser']):
-                    	    dep.properties['vcs-type'] = 'SVN'
-			else:
-			    # no chance to guess Vcs type
-                    	    dep.properties['vcs-type'] = 'Vcs'
-                        # There is no need to specify the Vcs-{Git,SVN} field in the tasks file but property 'vcs-type' should be set in
-                        # any case - so set it here in case it was not set before.  If an apropriate field is set later it becomes
-                        # overriden anyway
-                        if not dep.properties.has_key('vcs-url'):
-                            dep.properties['vcs-url'] = dep.properties['vcs-browser']
-                    else:
-                        logger.error("Dep not initiated before Vcs-Browser %s -> something is wrong." \
-                              % stanza['vcs-browser'])
-                    if dep.pkgstatus == 'unknown':
-                        dep.pkgstatus = 'pkgvcs'
-                elif key == 'section':
-                    if dep != None:
-                        dep.properties[key.lower()]  = stanza[key.lower()]
-                    else:
-                        logger.error("Dep not initiated before %s %s -> something is wrong." \
-                              % (key, stanza[key.lower()]))
-                elif key == 'License':
-                    if dep != None:
-                        dep.properties[key.lower()]  = stanza[key.lower()]
-                    else:
-                        logger.error("Dep not initiated before %s %s -> something is wrong." \
-                              % (key, stanza[key.lower()]))
-                elif key == 'Language':
-                    if dep != None:
-                        dep.properties[key.lower()]  = stanza[key.lower()]
-                    else:
-                        logger.error("Dep not initiated before %s %s -> something is wrong." \
-                              % (key, stanza[key.lower()]))
-                elif key == 'Registration':
-                    if dep != None:
-                        dep.properties[key.lower()]  = stanza[key.lower()]
-                    else:
-                        logger.error("Dep not initiated before %s %s -> something is wrong." \
-                              % (key, stanza[key.lower()]))
-                elif key.startswith('Published-'):
-                    if dep != None:
-                        if not dep.properties.has_key('published'):
-                            dep.properties['published'] = {}
-                        ptype = key.replace('Published-','').lower()
-                        dep.properties['published'][ptype] = to_unicode(stanza[key.lower()])
-                    else:
-                        logger.error("Dep not initiated before %s %s -> something is wrong." \
-                              % (key, stanza[key.lower()]))
-                elif key == 'WNPP':
-                    if dep != None:
-                        # it makes sense to assume that a package where WNPP was recently closed
-                        # shows up in unstable first
-                        if dep.component != None:
-                            logger.info("WNPP for package %s just closed - extra information can be removed from task file %s." % (dep.pkg, dep.taskname))
-                        else:
-                    	    wnpp = stanza['wnpp'].strip()
-                            # in case somebody prepended a '#' sign before the bug number
-                            wnpp = re.sub('^#', '', wnpp)
-                    	    # if there is really a number given
-                    	    if re.compile("^\d+$").search(wnpp):
-                        	dep.properties['wnpp'] = wnpp
-                    else:
-                        logger.error("Dep not initiated before WNPP %s -> something is wrong." \
-                              % stanza['wnpp'])
-                elif key.lower() == 'pkg-url':
-                    if dep != None:
-                        if dep.properties['pkg-url'] == HOMEPAGENONE: # only if no official package is just available
-                            # Escape '&' in URLs with %26 (Trick stolen by pasting the URL into a search engine ;-))
-                            dep.properties['pkg-url'] = stanza['pkg-url'].replace("&", "%26")
-                    else:
-                        logger.error("Dep not initiated before Pkg-URL %s -> something is wrong." \
-                              % stanza['pkg-url'])
-                elif key == 'Pkg-Description':
-                    if dep == None:
-                        logger.error("Dep not initiated before Pkg-Description %s -> something is wrong." \
-                              % stanza['pkg-description'].splitlines()[0])
-                    else:
-                        # Only update use description from task file if not known from official package
-                        if dep.desc['en'] == {}:
-                            (short, long) = SplitDescription(to_unicode(stanza['pkg-description']))
-                            dep.desc['en']['short'] = short
-                            dep.desc['en']['long']  = long
-                        else:
-                            fields_obsolete.append(key)
-                            continue
-                elif key == 'Avoid' or key == 'Ignore':
-                    dep.pkgstatus = key.lower()
-                elif key == 'Remark':
-                    (short, long) = SplitDescription(stanza['remark'])
-                    if dep == None:
-                        _pkg = self.metapkg.PrintedName
-                    else:
-                        _pkg = dep.pkg
-                    remark['short'] = MarkupString(short.encode('utf-8'), _pkg, 'RemarkShort')
-                    remark['long']  = MarkupString(long.encode('utf-8'),  _pkg, 'RemarkLong')
-                    continue
-                else:
-            	    if key not in KEYSTOIGNORE:
-                        # Also ignore keys starting with X[A-Z]-
-                        if not re.compile("^X[A-Z]*-").search(key):
-                            try:
-                                logger.warning("Unknown key '%s': %s in file %s" % (key, stanza[key], self.metapkg.PrintedName))
-                            except:
-                                logger.error("Unknown key '%s' with problematic value in file %s." % (key, self.metapkg.PrintedName))
-
-            if dep == None:
-                continue # ... with next stanza
-            # seek for certain field set in the tasks file to move the dependency into different
-            # categories of development status of not yet included packages
-            if dep.pkgstatus == 'unknown':
-                flag = 0
-                # first check those packages where some work was just done
-                for status in ['pkgvcs', 'unofficial', 'wnpp', 'prospective']:
-                    for field in pkgstatus[status]['fields-set']:
-                        if dep.properties.has_key(field):
-                            if field in HOMEPAGENONEFIELDS and dep.properties[field] == HOMEPAGENONE :
-                                continue
-                            dep.pkgstatus = status
-                            flag = 1
-                            break
-                    if flag == 1:
-                        break
-                if flag == 0:
-                    # If there was no such package found query UDD whether any package provides this name
-                    # This is often the case for libraries with versions in the package name
-                    query = "EXECUTE query_provides ('%s')" % (dep.pkg)
-                    curs.execute(query)
-                    if curs.rowcount > 0:
-                        has_expilicite = 0
-                        VirtProvides = []
-                        for row in curs.fetchall():
-                            VirtProvides.append(row[0])
-                            for hasdeps in tmp_dep_list:
-                                if row[0] == hasdeps.pkg:
-                                    logger.error("    --> %s is mentioned explicitely in dependency list" % row[0])
-                                    has_expilicite = 1
-                        if has_expilicite == 1:
-                            logger.error("Do not keep a record of virtual package %s which has explicite package dependencies" % dep.pkg)
-                            # ATTENTION: THIS HAS TO BE CHANGED FOR blends-dev BY AN OPTIONAL parameter
-                            continue
-
-                        logger.error("Use real package %s instead of virtual package %s." % (VirtProvides[0], dep.pkg))
-                        dep.pkg = VirtProvides[0]
-                        dep._QueryUDD4Package(source)
-
-                        if len(VirtProvides) > 1:
-                            logger.error("Virtual package %s is provided by more than one package (%s).  Make sure you mention a real package in addition!" \
-                                % (dep.pkg, str(VirtProvides)))
-
-                            for virt_provides in VirtProvides[1:]:
-                                # Add all remaining packages which provide a virtual package to the list
-                                if dep != None:
-                                    # Add the first real package from the packages which provide the virtual package to the list
-                                    tmp_dep_list.append(dep)
-                                dep = DependantPackage(self.blendname, self.task)
-                                # Store the comments in case they might be usefull for later applications
-                                dep.why            = why
-                                dep.responsible    = responsible
-                                dep.dep_strength   = key
-                                dep.pkg            = virt_provides
-                                dep._QueryUDD4Package(source)
-                    else:
-                        logger.warning("Dependency with unknown status: %s (Task %s)" % (dep.pkg, dep.taskname))
-
-            tmp_dep_list.append(dep)
-            # remarks which are common to several dependencies in a list have to be added to all of the dependencies
-            for dep in tmp_dep_list:
-                if remark != {}:
-                    dep.remark = remark
-                if fields_obsolete != [] and dep.pkgstatus != 'new':
-                    logger.info("Package %s is an official package and has information in UDD. The following extra information can be removed from tasks file %s: %s" % \
-                                     (dep.pkg, dep.taskname, str(fields_obsolete)))
-                if dep.desc['en'] == {}:
-                    logger.error("Missing description for package %s in task %s.  This package will be ignored completely." % (dep.pkg, dep.taskname))
-                else:
-                    self._AppendDependency2List(dep, source)
-
-        f.close()
-
-        for dependency in self.dependencies.keys():
-            self.dependencies[dependency].sort()
-
-    def MarkupPreformatedStrings(self):
-        # Genshi does not touch strings that are marked with "Markup()" - so just
-        # mark the strings that are ready formatted
-
-        for dependency in self.dependencies.keys():
-            for dep in self.dependencies[dependency]:
-                dep.responsible         = MarkupString(dep.responsible, dep.pkg, 'responsible')
-                if dep.desc['en'] != {}:
-                    dep.desc['en']['short'] = MarkupString(dep.desc['en']['short'], dep.pkg, 'pkgShortDesc')
-                    dep.desc['en']['long']  = MarkupString(dep.desc['en']['long'],  dep.pkg, 'pkgLongDesc')
-
-    def __str__(self):
-        ret = "Blend: " + self.blendname + ", " \
-              "Task:"   + self.task      + ", " \
-              "Dependencies:" + str(self.dependencies)
-        return ret
-
-
-class Available:
-    # Information about available packages
-    #
-    # Usage example:
-    #    available = Available(                     # Initialize instance
-    #                          release='testing',      # (default='unstable')
-    #                          components=('main'), # Regard only main, default: main, contrib, non-free
-    #                          source=1             # Use source package names, default: use binaries
-    #                          arch='sparc'         # (default='i386')
-    #                         )
-    # 
-    #    available.GetPackageNames() # Actually parse the Packages files to obtain needed information
-    #                                # This has to be done at least once.  It is verified that the effort
-    #                                # to obtain package information is not done twice per run
-
-    def __init__(self, release=None, components=(), source=None, arch=None, method=None):
-        if method == 'UDD':
-            self.__init_UDD__(release=release, components=components, source=source, arch=arch)
-        else:
-            self.__init_Packages_gz__(release=release, components=components, source=source, arch=arch)
-
-
-    def __init_Packages_gz__(self, release=None, components=(), source=None, arch=None):
-        self.source = 'Packages.'+COMPRESSIONEXTENSION
-        if source != None:
-            self.source = 'Sources.'+COMPRESSIONEXTENSION
-        self.binary = 'source'
-        if source == None:
-            if arch == None:
-                # use arch=i386 as default because it contains most packages
-                self.binary = 'binary-i386'
-            else:
-                self.binary = 'binary-' + arch
-        self.release = 'unstable'
-        if release != None:
-            self.release = release
-        self.components = ('main', 'contrib', 'non-free')
-        if components != ():
-            self.components = components
-        # The dictionary packages contains the component as key
-        # The values are dictionaries holding package names as key
-        # and a DependantPackage object as values
-        self.packages = {}
-        for component in self.components:
-            self.packages[component] = {}
-
-
-##################################################################################################
-# bugs
-
-SEVERITIES = ('critical', 'grave', 'serious', 'important', 'normal', 'minor', 'wishlist')
-
-# Obtain description in foreign language from DDTP project if available
-# For the moment just query for the highest available version of the description
-query = """PREPARE bugs_query_source (text) AS
-           SELECT id, package, source, status, severity, done, title FROM bugs WHERE source = $1"""
-curs.execute(query)
-
-query = """PREPARE bugs_query_tags (int) AS SELECT tag FROM bugs_tags WHERE id = $1"""
-curs.execute(query)
-
-class BugEntry:
-    # Define a separate class for bug entries to be able to define a reasonably sorting mechanism
-    # It seems that Genshi templates are unable to handle bug objects and so the essential parts
-    # are taken over here in addition to a __cmp__ method to enable easy sorting of list of bugs
-    # Rationale: Calling methods inside the template does not
-    #            seem to work and has to be done in any case to
-    #            circumvent encoding problems
-
-    def __init__(self, bug):
-        self.bug      = bug['id']
-	self.summary  = to_unicode(bug['title'])
-	self.severity = bug['severity']
-
-        query = "EXECUTE bugs_query_tags (%i)" % self.bug
-        curs.execute(query)
-
-        self.tags     = ''
-        if curs.rowcount > 0:
-            komma = ''
-            for tag in curs.fetchall():
-		self.tags += komma + tag[0]
-		komma = ', '
-
-    # sort these objects according to bug number
-    def __cmp__(self, other):
-        # Comparing with None object has to return something reasonable
-        if other == None:
-            return -2
-        # Sort according to package name
-        return cmp(self.bug, other.bug)
-
-class PackageBugs:
-    # Store list of bugs (either open or done) of a package
-
-    def __init__(self, pkgdict):
-        self.pkgname    = pkgdict['pkgname']
-        self.source     = pkgdict['source']
-        self.homepage   = pkgdict['homepage']
-        self.vcsbrowser = pkgdict['vcs-browser']
-        self.maintainer = MarkupString(pkgdict['maintainer'], self.pkgname, 'maintainer')
-	self.bugs       = []      # open bugs
-	self.nbugs      = 0
-	self.severities = {}
-	for s in SEVERITIES:
-		self.severities[s] = 0
-
-    # sort these objects according to the package name
-    def __cmp__(self, other):
-        # Comparing with None object has to return something reasonable
-        if other == None:
-            return -2
-        # Sort according to package name
-        return cmp(self.pkgname, other.pkgname)
-
-    def __str__(self):
-        str = "---\npkgname: %s\nsource: %s\n" % (self.pkgname, self.source)
-	if self.homepage:
-            str += "homepage: %s\n" % (self.homepage)
-	if self.vcsbrowser:
-            str += "vcsbrowser: %s\n" % (self.vcsbrowser)
-        return str + "nbugs: %s\nnbugs = %i\nseverities = %s\n---" % (self.nbugs, self.severities)
-
-
-class PackageBugsOpenAndDone:
-    # Store list of bugs of a package
-
-    def __init__(self, pkgdict):
-	pkgname = pkgdict['pkgname']
-	source  = pkgdict['source']
-	self.open       = PackageBugs(pkgdict)  # open bugs
-	self.done       = PackageBugs(pkgdict)  # closed bugs
-
-	bugs = None
-        query = "EXECUTE bugs_query_source ('%s')" % source
-        curs.execute(query)
-
-        if curs.rowcount > 0:
-            for bug in RowDictionaries(curs):
-                bugentry = BugEntry(bug)
-                if bug['status'] == 'done':
-                    if self.done.pkgname == None:
-                        self.done.pkgname = pkgname
-                    self.done.bugs.append(bugentry)
-                    self.done.nbugs += 1
-                else:
-                    if self.open.pkgname == None:
-                        self.open.pkgname = pkgname
-                    self.open.bugs.append(bugentry)
-                    self.open.nbugs += 1
-                    self.open.severities[bugentry.severity] += 1
-            self.open.bugs.sort()
-            self.done.bugs.sort()
-            if source == None:
-                self.open.source = pkgname
-                self.done.source = pkgname
-            else:
-                self.open.source = source
-                self.done.source = source
-
diff --git a/webtools/bugs.py b/webtools/bugs.py
index f322086..c0faa3b 100755
--- a/webtools/bugs.py
+++ b/webtools/bugs.py
@@ -1,291 +1,484 @@
 #!/usr/bin/python
-# Bugs of source packages in tasks
+# Copyright 2013: Andreas Tille <tille at debian.org>
+# License: GPL
 
+#PORT=5441
+UDDPORT=5452
+PORT=UDDPORT
+DEFAULTPORT=5432
+
+SLOWQUERYREPORTLIMIT=30
+
+debug=0
+
+from sys import argv, stderr, exit
 import os
-from sys import argv, exit, stderr
-import gettext
+import psycopg2
+import json
+import re
 import time
 from datetime import datetime
 from email.Utils import formatdate
+import email.Utils
+import gettext
 
 from genshi.template import TemplateLoader
 from genshi import Markup
+from genshi.template.eval import UndefinedError
 
-from blendstasktoolsold import Tasks, ReadConfig, PackageBugsOpenAndDone, \
-                            DEPENDENT, SUGGESTED, DONE, BUGLISTCAT, SEVERITIES, HOMEPAGENONE
-from blendstasktools import CheckOrCreateOutputDir
-
-if len(argv) <= 1:
-	print >>stderr, "Usage: %s <Blend name>\n       The <Blend name> needs a matching config file webconf/<Blend name>.conf"\
-                        % argv[0]
-	exit(-1)
+from blendsunicode   import to_unicode
+from blendstasktools import ReadConfig, RowDictionaries, CheckOrCreateOutputDir, SetFilePermissions
+from blendsmarkdown  import MarkupString
 
-# Sense of weight: We want to find a measure how much care a metapackage needs.
-# So we build the weighted sums of bugs and define limits for the status
-# The weights below are used for suggested packages.  In case a package has
-# a stronger dependency (Depends, Recommends) the weight is multiplied by 3
-weight = { 'critical'  : 10,
-	   'grave'     : 10,
-           'serious'   : 10,
-           'important' :  5,
-	   'normal'    :  3,
-           'minor'     :  1,
-           'wishlist'  :  0
-         }
-BAD          = 100 # if weighted bug sum >= BAD, the meta package is in a bad shape
-                   # Dependent packages might have 3 or more 5 RC bugs
-PASS         =  70 # this deserves a look - potentially two RC bugs in dependent packages
-SATISFACTORY =  50 # consider looking at this
-GOOD         =  30 # at least no RC bug in a dependent package
-VERYGOOD     =  10 # nothing burning
-EXCELLENT    =   5 # There is no real need to look at this meta package
-
-
-class BugList:
-    # We have three category of bugs:
-    #  1. open bugs in dependent and recommended packages
-    #  2. open bugs in suggested packages
-    #  3. closed bugs (closed bugs are fine - there is no need to classify
-    #     these according to dependency status)
-    # For each metapackage contains a buglist for each category is created
-    def __init__(self, category, source=None):
-	    if category not in BUGLISTCAT:
-		    print >>stderr, "The category value of a BugList object can only be (%s), %s is invalid." % \
-			( str(BUGLISTCAT), str(category) )
-		    return None
-
-	    self.pkgbugs  = [] # list of PackageBugs elements
-	    self.category = category
-
-	    self.severities = {}
-	    for s in SEVERITIES:
-		    self.severities[s] = 0
+###########################################################################################
+# Define several prepared statements to query UDD
+try:
+  conn = psycopg2.connect(host="localhost",port=PORT,user="guest",database="udd")
+except psycopg2.OperationalError, err:
+  try:
+    conn = psycopg2.connect("service=udd")
+  except psycopg2.OperationalError, err:
+    # logger not known at this state: logger.warning
+    print >>stderr, "Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err))
+    try:
+        conn = psycopg2.connect(host="localhost",port=DEFAULTPORT,user="guest",database="udd")
+    except psycopg2.OperationalError:
+	# Hmmm, I observed a really strange behaviour on one of my machines where connecting to
+	# localhost does not work but 127.0.0.1 works fine.  No idea why ... but this should
+	# do the trick for the moment
+	conn = psycopg2.connect(host="127.0.0.1",port=DEFAULTPORT,user="guest",database="udd")
 
-    def append(self, pkgbug):
-	    # Append PackageBug opject to the list and update bug statistics
-	    self.pkgbugs.append(pkgbug)
-	    for s in SEVERITIES:
-		    self.severities[s] += pkgbug.severities[s]
+curs = conn.cursor()
+# uddlog = open('logs/uddquery.log', 'w')
 
-    def __str__(self): 
-	    ret = ''
-	    if self.pkgbugs != []:
-		    for pkgbug in self.pkgbugs:
-			    ret += str(pkgbug) + "\n"
-	    else:
-		    ret = 'empty list of bugs'
-	    return "pkgbugs: %s\nseverities: %s" % (ret, str(self.severities))
+def _execute_udd_query(query):
+    try:
+        t = time.time()
+        curs.execute(query)
+        elapsed_time = time.time() - t
+        if elapsed_time > SLOWQUERYREPORTLIMIT: # report what query took longer than SLOWQUERYREPORTLIMIT seconds
+            print "Time: %s\nQuery: %s" % (str(elapsed_time), query)
+    except psycopg2.ProgrammingError, err:
+        print >>stderr, "Problem with query\n%s" % (query)
+        print >>stderr, err
+        exit(-1)
+    except psycopg2.DataError, err:
+        print >>stderr, "%s; query was\n%s" % (err, query)
 
-# Define directories used
-current_dir  = os.path.dirname(__file__)
-locale_dir   = os.path.join(current_dir, 'locale')
-template_dir = os.path.join(current_dir, 'templates')
 
-# Initialize i18n
-domain = 'blends-webtools'
-gettext.install(domain)
+def main():
 
-# initialize gensi
-loader = TemplateLoader([template_dir], auto_reload=True)
+    if len(argv) <= 1:
+        print >>stderr, "Usage: %s <Blend name>" % argv[0]
+        exit(-1)
 
-tasks    = Tasks(argv[1])
-if tasks.data['pkglist'] == '':
-	print >>stderr, "Config file webconf/%s.conf is lacking pkglist field." % (argv[1])
-	exit(-1)
-tasks.GetAllDependencies(source=1) # Set source=1 in case source packages should be displayed
-packages = tasks.GetNamesAndSourceDict(dependencystatus=('official_high', 'official_low', 'non-free', 'experimental'))
+    blendname = argv[1]
+    config = ReadConfig(blendname)
 
-outputdir = CheckOrCreateOutputDir(tasks.data['outputdir'],'bugs')
-if outputdir == None:
-	exit(-1)
+    # Metadata of packages that might have bugs
+    query = """PREPARE query_bug_packages (text) AS
+      SELECT distinct sources.source, task, CASE WHEN (tasks.dependency = 'd' OR tasks.dependency = 'r') AND component = 'main' AND experimental_flag > 0 THEN 'depends' ELSE 'suggests' END AS status,
+                      homepage, CASE WHEN vcs_browser IS NULL THEN '#' ELSE vcs_browser END AS vcs_browser, maintainer
+        FROM (
+          SELECT s.source, b.component, s.homepage, s.vcs_browser, s.maintainer, s.version, row_number() OVER (PARTITION BY s.source ORDER BY s.version DESC)
+            FROM blends_dependencies b
+            JOIN packages p ON p.package = b.package
+            JOIN bugs bu    ON bu.source = p.source
+            JOIN sources s  ON s.source  = p.source
+            WHERE blend = $1 AND b.distribution = 'debian'
+        ) sources
+        -- check status of dependency relation because only suggested packages are less important for bugs sentinel
+        LEFT OUTER JOIN (
+          SELECT source, task, dependency FROM (
+            SELECT p.source, b.task, bdp.dependency, row_number() OVER (PARTITION BY p.source, b.task ORDER BY bdp.priority)
+              FROM packages p
+              JOIN blends_dependencies b ON b.package = p.package
+              JOIN sources s ON p.source = s.source AND p.release = s.release
+              JOIN blends_dependencies_priorities bdp ON b.dependency = bdp.dependency
+              WHERE b.blend = $1
+          ) tmp
+          WHERE row_number = 1
+        ) tasks ON sources.source = tasks.source
+        -- Check, whether a package is in experimental only which makes it less important for bugs sentinel
+        LEFT OUTER JOIN (
+          SELECT source, MAX(sort) AS experimental_flag FROM sources s
+            JOIN releases r ON s.release = r.release
+          GROUP BY source
+        ) exp ON sources.source = exp.source
+        WHERE row_number = 1
+        ORDER BY source;
+    """
+    _execute_udd_query(query)
 
-t = datetime.now()
-data = tasks.data
-data['tasks']             = tasks.GetTaskDescDict()
-data['taskskeys']         = tasks.metapackagekeys
-data['lang']              = 'en'
-data['othertasks']        = _("Links to other tasks")
-data['taskslink']         = _("Tasks")
-data['bugslink']          = _("Tasks overview")
-data['legend']            = _("Legend")
-data['bugsofpackage']     = _("Bugs of package")
-data['totalbugs']         = _("Total bugs")
-data['openbugs']          = _("Open bugs")
-data['fixedbugs']         = _("Fixed bugs")
-data['summary']           = _('Summary')
-data['bugssummary']       = _("""A %sDebian Pure Blend%s is a Debian internal project which assembles
-a set of packages that might help users to solve certain tasks of their work.  This page should be helpful
-to track down the bugs of packages that are interesting for the %s project to enable developers a quick
-overview about possible problems.""" ) \
-                                      % ('<a href="http://blends.alioth.debian.org/blends/">', '</a>', data['projectname'])
-data['bugssummary']        = Markup(data['bugssummary'])
-data['gtstrBugsPage']     = _("Bugs page")
-data['gtstrListOfBugspages'] = _("This is a list of metapackages.  The links are leading to the respective bugs page.")
-data['updatetimestamp']   = _('Last update:') + ' ' + formatdate(time.mktime(t.timetuple()))
-data['weightexplanation'] = _("""To estimate the overall status of the packages in the dependencies of
-a metapackage a weighted severity is calculated.  Done bugs are ignored and bugs in dependent and
-recommended packages are weighted by factor three compared to suggested packages.  Release critical
-bugs have a much larger weight than important, while the contribution of normal bugs is even smaller
-and minor bugs have a very small weight.  Wishlist bugs are ignored in this calculation.  The resulting
-sum is compared to some boundaries to find a verbal form.  The actual numbers need some adjustment
-to make real sense - this evaluation method is in testing phase.""")
-data['weightdetails']     = _("The severities of bugs are weighted as follows")
+    # Actual bugs in packages of Blends dependencies
+    query = """PREPARE query_bugs (text) AS
+      SELECT source, bu.id, title, severity, status, done_by, tags FROM (
+        SELECT distinct bu.source, bu.id, bu.title, bu.severity, bu.status, bu.done AS done_by
+          FROM blends_dependencies b
+          JOIN packages p ON p.package = b.package
+          JOIN bugs bu    ON bu.source = p.source
+          WHERE blend = $1 AND b.distribution = 'debian'
+        ) bu
+        LEFT OUTER JOIN (
+          SELECT id, array_agg(tag) AS tags FROM bugs_tags GROUP BY id
+        ) bt ON bu.id = bt.id
+        ORDER BY source, bu.id;
+    """
+    _execute_udd_query(query)
+    
+    # What tasks are involved
+    query = """PREPARE query_get_tasks (text) AS
+      SELECT task, title, description, long_description FROM blends_tasks WHERE blend = $1 ORDER BY task;
+    """
+    _execute_udd_query(query)
 
-if data['advertising'] != None:
-	# If data['advertising'] is enclosed in _() gettext tries to ask for translations of 'advertising'
-	# which makes no sense.  That's why this is masked by an extra string variable
-	advertising = data['advertising']
-	##data['projectadvertising'] = _(advertising) # Hopefully translation will work this way ...
-	# Genshi needs explicite information that it is dealing with an UTF-8 string which should not be changed
-	advertising = _(advertising)
-	data['projectadvertising'] = Markup(unicode(advertising))# , 'utf-8'))
-else:
-	data['projectadvertising'] = None
+    STATES = ['depends', 'suggests', 'done']
+    SEVERITIES = ('critical', 'grave', 'serious', 'important', 'normal', 'minor', 'wishlist')
 
-data['assessments']     = [ (EXCELLENT,    'excellent'),
-			    (VERYGOOD,     'verygood'),
-                            (GOOD,         'good'),
-                            (SATISFACTORY, 'satisfactory'),
-			    (PASS,         'pass'),
-			    (BAD,          'bad')
-                          ]
+    # Sense of weight: We want to find a measure how much care a metapackage needs.
+    # So we build the weighted sums of bugs and define limits for the status
+    # The weights below are used for suggested packages.  In case a package has
+    # a stronger dependency (Depends, Recommends) the weight is multiplied by 3
+    WEIGHT = { 'critical'  : 10,
+               'grave'     : 10,
+               'serious'   : 10,
+               'important' :  5,
+               'normal'    :  3,
+               'minor'     :  1,
+               'wishlist'  :  0
+             }
+    BAD          = 100 # if weighted bug sum >= BAD, the meta package is in a bad shape
+                       # Dependent packages might have 3 or more 5 RC bugs
+    PASS         =  70 # this deserves a look - potentially two RC bugs in dependent packages
+    SATISFACTORY =  50 # consider looking at this
+    GOOD         =  30 # at least no RC bug in a dependent package
+    VERYGOOD     =  10 # nothing burning
+    EXCELLENT    =   5 # There is no real need to look at this meta package
 
-nbugs           = {}
-ndone           = {}
-buglist         = {}
-severitysummary = {} # Number of bugs in different severity / dependency classes
-weightedsev     = {} # verbal interpretation of weighted bugs
-weightedclass   = {} # CSS class according bug weight
-weighttask      = {} # weighted severity as number per task
-severitystat    = {} # Count bugs with different severities per task
-for task in packages.keys():
-	pkgbugs       = []
-	nbugs[task]   = 0
-	ndone[task]   = 0
-	buglist[task] = {}
-	for cat in BUGLISTCAT:
-		buglist[task][cat] = BugList(cat)
+    # initialise bugs_data dictionary for all tasks
+    _execute_udd_query( "EXECUTE query_get_tasks('%s')" % blendname)
+    bugs_data = {}
+    if curs.rowcount > 0:
+        for t in RowDictionaries(curs):
+            task = t['task']
+            bugs_data[task] = {}
+            bugs_data[task]['title']		= t['title']
+            bugs_data[task]['description']	= t['description']
+            bugs_data[task]['long_description']	= to_unicode(t['long_description'])
+            bugs_data[task]['nopenbugs']	= 0
+            bugs_data[task]['ndonebugs']	= 0
+            bugs_data[task]['weighttask']	= 0
+            for status in STATES:
+                bugs_data[task][status + '_l']     = [] # enable sorting
+                bugs_data[task][status]            = {}
+                bugs_data[task][status]['sources'] = []
+                if status != 'done':
+                    bugs_data[task][status]['severitysummary'] = '' # string listing number of bugs in different severity / dependency classes
+                    bugs_data[task][status]['severities'] = {}
+                    for s in SEVERITIES:
+                        bugs_data[task][status]['severities'][s] = 0
+    else:
+        print >>stderr, "No tasks metadata received for Blend", blendname
+        exit(1)
 
-	# query bugs of meta package name
-	pkg = { 'pkgname'    : data['tasks'][task].metapkg.pkg,
-		'source'     : None,
-		'homepage'   : None,
-		'vcs-browser': None,
-		'maintainer' : None,
-	      }
-	if data['tasks'][task].metapkg.properties['vcs-browser'] != HOMEPAGENONE:
-		pkg['vcs-browser'] = data['tasks'][task].metapkg.properties['vcs-browser']
-	if data['tasks'][task].metapkg.responsible != None:
-		pkg['maintainer']  = data['tasks'][task].metapkg.responsible
-	pkgbug_oad = PackageBugsOpenAndDone(pkg)
-	# the metapackage itself belongs to the list do dependent packages
-	if pkgbug_oad.open.pkgname:
-		buglist[task][DEPENDENT].append(pkgbug_oad.open)
-		nbugs[task] += pkgbug_oad.open.nbugs
-	if pkgbug_oad.done.pkgname:
-		buglist[task][DONE].append(pkgbug_oad.done)
-		ndone[task] += pkgbug_oad.done.nbugs
+    # Fetch bugs of all Blends dependencies and store them in a dictionary
+    _execute_udd_query( "EXECUTE query_bugs('%s')" % blendname)
+    bugs = {}
+    if curs.rowcount > 0:
+        for bug in RowDictionaries(curs):
+            if not bugs.has_key(bug['source']):
+                bugs[bug['source']] = {}
+                bugs[bug['source']]['severities'] = {}
+                for s in SEVERITIES:
+                    bugs[bug['source']]['severities'][s] = 0
+                bugs[bug['source']]['nopenbugs'] = 0
+                bugs[bug['source']]['ndonebugs'] = 0
+                bugs[bug['source']]['open'] = []
+                bugs[bug['source']]['done'] = []
+            b = {}
+            for k in bug.keys():
+                if k in ('source', 'status') :
+                    continue
+                if k == 'title':
+                    b[k] = to_unicode(bug[k])
+                elif k == 'tags':
+                    komma = ''
+                    b['tags'] = ''
+                    if bug[k]:
+                        for tag in bug[k]:
+                           b['tags'] += komma + tag
+                           komma      = ', '
+                else:
+                    b[k] = bug[k]
+            if bug['status'] == 'done':
+                bugs[bug['source']]['done'].append(b)
+                bugs[bug['source']]['ndonebugs'] += 1
+            else:
+                bugs[bug['source']]['open'].append(b)
+                bugs[bug['source']]['nopenbugs'] += 1
+                bugs[bug['source']]['severities'][bug['severity']] += 1
+    else:
+        print >>stderr, "No bug data received for Blend", blendname
+        exit(1)
 
-	for pkg in packages[task]:
-		pkgbug_oad = PackageBugsOpenAndDone(pkg)
-		if pkgbug_oad.open.pkgname:
-			buglist[task][pkg['bugrelevantdependency']].append(pkgbug_oad.open)
-		if pkgbug_oad.done.pkgname:
-			buglist[task][DONE].append(pkgbug_oad.done)
-		nbugs[task] += pkgbug_oad.open.nbugs
-		ndone[task] += pkgbug_oad.done.nbugs
+    # Merge metadata of packages and bugs together in bugs_data dictionary, also do statistics about bugs
+    _execute_udd_query( "EXECUTE query_bug_packages('%s')" % blendname)
+    if curs.rowcount > 0:
+        for pkg in RowDictionaries(curs):
+                task = pkg['task']
+                sources = {}
+                sources['source']      = pkg['source']
+                sources['homepage']    = pkg['homepage']
+                sources['vcs_browser'] = pkg['vcs_browser']
+                (_name, _url) = email.Utils.parseaddr(pkg['maintainer'])
+                sources['maintainer_email'] = _url
+                sources['maintainer_name']  = to_unicode(_name)
+                sources['maintainer']  = MarkupString('<a href="mailto:%s">%s</a>' % (_url, to_unicode(_name)), pkg['source'], 'maintainer')
+                if pkg['status'] == 'depends':
+                    sources['bugs'] = bugs[pkg['source']]['open']
+                    bugs_data[task][pkg['status']+'_l'].append(pkg['source'])
+                    for s in SEVERITIES:
+                        bugs_data[task][pkg['status']]['severities'][s] += bugs[pkg['source']]['severities'][s]
+                        bugs_data[task]['weighttask'] += 3 * WEIGHT[s] * bugs[pkg['source']]['severities'][s]
+                elif pkg['status'] == 'suggests':
+                    sources['bugs'] = bugs[pkg['source']]['open']
+                    bugs_data[task][pkg['status']+'_l'].append(pkg['source'])
+                    for s in SEVERITIES:
+                        bugs_data[task][pkg['status']]['severities'][s] += bugs[pkg['source']]['severities'][s]
+                        bugs_data[task]['weighttask'] += 1 * WEIGHT[s] * bugs[pkg['source']]['severities'][s]
+                else:
+                    print >>stderr, "%s: Wrong status %s in task %s for source %s" % (blendname, pkg['status'], task, pkg['source'])
+                    exit(1)
+                bugs_data[task][pkg['status']]['sources'].append(sources)
+                bugs_data[task]['nopenbugs'] += bugs[pkg['source']]['nopenbugs']
+                bugs_data[task]['ndonebugs'] += bugs[pkg['source']]['ndonebugs']
+                if bugs[pkg['source']]['done']:
+                    sources = {}
+                    sources['source']      = pkg['source']
+                    sources['homepage']    = pkg['homepage']
+                    sources['vcs_browser'] = pkg['vcs_browser']
+                    (_name, _url) = email.Utils.parseaddr(pkg['maintainer'])
+                    sources['maintainer_email'] = _url
+                    sources['maintainer_name']  = to_unicode(_name)
+                    sources['maintainer']  = MarkupString('<a href="mailto:%s">%s</a>' % (_url, to_unicode(_name)), pkg['source'], 'maintainer')
+                    sources['bugs']        = bugs[pkg['source']]['done']
+                    bugs_data[task]['done_l'].append(pkg['source'])
+                    bugs_data[task]['done']['sources'].append(sources)
+    else:
+        print >>stderr, "No information about buggy packages received for Blend", blendname
+        exit(1)
 
-	severitysummary[task] = {}
-	wsev = 0  # sumarise weighted severities
-	severitystat[task] = {}
-	for cat in BUGLISTCAT:
-		curbuglist = buglist[task][cat]
-		if len(curbuglist.pkgbugs) > 0:
-			# sort lists of PkgBug objects inside the three categories
-			curbuglist.pkgbugs.sort()
-		severitysummary[task][cat] = ''
-		severitystat[task][cat] = {}
-		if cat != DONE:
-			sevsum = ''
-			komma  = ''
-			fac = 1
-			if cat == DEPENDENT:
-				fac = 3
-			for s in SEVERITIES:
-				if curbuglist.severities[s] > 0:
-					sevsum += komma + str(curbuglist.severities[s]) + ' ' + s
-					komma   = ', '
-				severitystat[task][cat][s] = curbuglist.severities[s]
-				# calculate weighted severity for whole metapackage
-				wsev += fac * weight[s] * curbuglist.severities[s]
-			severitysummary[task][cat] = sevsum
-	if   wsev < data['assessments'][0][0]:
-		weightedsev[task]   = _('Metapackage is in excellent shape')
-		weightedclass[task] = data['assessments'][0][1]
-	elif wsev < data['assessments'][1][0]:
-		weightedsev[task]   = _('Metapackage is in very good shape')
-		weightedclass[task] = data['assessments'][1][1]
-	elif wsev < data['assessments'][2][0]:
-		weightedsev[task]   = _('Metapackage is in good shape')
-		weightedclass[task] = data['assessments'][2][1]
-	elif wsev < data['assessments'][3][0]:
-		weightedsev[task]   = _('Consider looking into bugs of this metapackage')
-		weightedclass[task] = data['assessments'][3][1]
-	elif wsev < data['assessments'][4][0]:
-		weightedsev[task]   = _('Looking into bugs of this metapackage is recommended')
-		weightedclass[task] = data['assessments'][4][1]
-	else:
-		weightedsev[task]   = _('Immediately looking into bugs of the dependencies of this metapackage is advised')
-		weightedclass[task] = data['assessments'][5][1]
-	weightedsev[task] += ' (%i)' % wsev
-	weighttask[task]   = wsev
+    # Define directories used
+    current_dir  = os.path.dirname(__file__)
+    # locale_dir   = os.path.join(current_dir, 'locale')
+    template_dir = os.path.join(current_dir, 'templates')
+    
+    # initialize gensi
+    loader = TemplateLoader([template_dir], auto_reload=True)
+    
+    outputdir = CheckOrCreateOutputDir(config['outputdir'],'bugs') # FIXME: as long as we are not finished use different dir
+    if outputdir == None:
+            exit(-1)
+    
+    t = datetime.now()
+    
+    # Initialize i18n
+    domain = 'blends-webtools'
+    gettext.install(domain)
 
-data['headings'] = {DEPENDENT : _('Open bugs in dependent packages'),
-                    SUGGESTED : _('Open bugs in suggested packages'),
-                    DONE      : _('Done bugs')
-                   }
-data['nobugs']   = {DEPENDENT : _('No open bugs in dependent packages'),
-                    SUGGESTED : _('No open bugs in suggested packages'),
-                    DONE      : _('No done bugs')
-                   }
-data['cssclass'] = {DEPENDENT : 'bugsdependent',
-                    SUGGESTED : 'bugssuggested',
-                    DONE      : 'bugsdone'
-                   }
+    data={}
+    data['projectname'] = blendname
+    data['bugs_data']   = bugs_data
+    if config.has_key('advertising') and config['advertising'] != None:
+        # we have to remove the gettext _() call which was inserted into the config
+        # file to enable easy input for config file editors - but the call has to
+        # be made explicitely in the python code
+        advertising = re.sub('_\(\W(.+)\W\)', '\\1', config['advertising'])
+        # gettext needs to escape '"' thus we need to remove the escape character '\'
+        data['projectadvertising'] = Markup(to_unicode(re.sub('\\\\"', '"', advertising)))
+    else:
+        data['projectadvertising'] = None
 
-data['nbugs']           = nbugs
-data['ndone']           = ndone
-data['buglistcat']      = BUGLISTCAT
-data['severities']      = SEVERITIES
-data['weight']          = weight
-data['DEPENDENT']       = DEPENDENT
-data['SUGGESTED']       = SUGGESTED
-data['nohomepage']      = _('Homepage not available')
-data['novcsbrowser']    = _('Not maintained in Vcs')
-data['vcslocation']     = _('Vcs')
+    data['summary']           = to_unicode(_('Summary'))
+    data['idxsummary']        = to_unicode(_("""A %sDebian Pure Blend%s is a Debian internal project which assembles
+a set of packages that might help users to solve certain tasks of their work.  The list on
+the right shows the tasks of %s.""" ) \
+                                      % ('<a href="http://blends.alioth.debian.org/blends/">', '</a>', data['projectname']))
+    data['idxsummary']        = Markup(to_unicode(data['idxsummary']))
 
-data['weighttask']      = weighttask
-data['weightedclass']   = weightedclass
+    t = datetime.now()
+    data['lang']              = 'en'
+    data['othertasks']        = _("Links to other tasks")
+    data['taskslink']         = _("Tasks")
+    data['bugslink']          = _("Tasks overview")
+    data['legend']            = _("Legend")
+    data['bugsoftask']        = _("Bugs of task")
+    data['totalbugs']         = _("Total bugs")
+    data['openbugs']          = _("Open bugs")
+    data['fixedbugs']         = _("Fixed bugs")
+    data['summary']           = _('Summary')
+    data['bugssummary']       = _("""A %sDebian Pure Blend%s is a Debian internal project which assembles
+    a set of packages that might help users to solve certain tasks of their work.  This page should be helpful
+    to track down the bugs of packages that are interesting for the %s project to enable developers a quick
+    overview about possible problems.""" ) \
+                                          % ('<a href="http://blends.alioth.debian.org/blends/">', '</a>', data['projectname'])
+    data['bugssummary']        = Markup(data['bugssummary'])
+    data['gtstrBugsPage']     = _("Bugs page")
+    data['gtstrListOfBugspages'] = _("This is a list of metapackages.  The links are leading to the respective bugs page.")
+    data['updatetimestamp']   = _('Last update:') + ' ' + formatdate(time.mktime(t.timetuple()))
+    data['weightexplanation'] = _("""To estimate the overall status of the packages in the dependencies of
+    a metapackage a weighted severity is calculated.  Done bugs are ignored and bugs in dependent and
+    recommended packages are weighted by factor three compared to suggested packages.  Release critical
+    bugs have a much larger weight than important, while the contribution of normal bugs is even smaller
+    and minor bugs have a very small weight.  Wishlist bugs are ignored in this calculation.  The resulting
+    sum is compared to some boundaries to find a verbal form.  The actual numbers need some adjustment
+    to make real sense - this evaluation method is in testing phase.""")
+    data['weightdetails']     = _("The severities of bugs are weighted as follows")
+    
+    data['assessments']     = [ (EXCELLENT,    'excellent'),
+                                (VERYGOOD,     'verygood'),
+                                (GOOD,         'good'),
+                                (SATISFACTORY, 'satisfactory'),
+                                (PASS,         'pass'),
+                                (BAD,          'bad')
+                              ]
+    
+    for task in bugs_data:
+        if bugs_data[task]['weighttask'] < data['assessments'][0][0]:
+            bugs_data[task]['weightedsev']   = _('Task is in excellent shape')
+            bugs_data[task]['weightedclass'] = data['assessments'][0][1]
+        elif bugs_data[task]['weighttask'] < data['assessments'][1][0]:
+            bugs_data[task]['weightedsev']   = _('Task is in very good shape')
+            bugs_data[task]['weightedclass'] = data['assessments'][1][1]
+        elif bugs_data[task]['weighttask'] < data['assessments'][2][0]:
+            bugs_data[task]['weightedsev']   = _('Task is in good shape')
+            bugs_data[task]['weightedclass'] = data['assessments'][2][1]
+        elif bugs_data[task]['weighttask'] < data['assessments'][3][0]:
+            bugs_data[task]['weightedsev']   = _('Consider looking into bugs of this task')
+            bugs_data[task]['weightedclass'] = data['assessments'][3][1]
+        elif bugs_data[task]['weighttask'] < data['assessments'][4][0]:
+            bugs_data[task]['weightedsev']   = _('Looking into bugs of this task is recommended')
+            bugs_data[task]['weightedclass'] = data['assessments'][4][1]
+        else:
+            bugs_data[task]['weightedsev']   = _('Immediately looking into bugs of the dependencies of this task is advised')
+            bugs_data[task]['weightedclass'] = data['assessments'][5][1]
+        bugs_data[task]['weightedsev']   +=  ' (%i)' % bugs_data[task]['weighttask']
 
-for task in packages.keys():
-	data['task']            = task
-	data['buglist']         = buglist[task]
-	data['severitysummary'] = severitysummary[task]
-	data['weightedsev']     = weightedsev[task]
-	data['severitystat']    = severitystat[task]
+    # Debuging output in JSON file
+    if debug > 0:
+        f = open(blendname+'_bugs.json', 'w')
+        if debug > 1:
+            for task in bugs_data:
+                print >>f, "*** %s ***" % task
+                for status in STATES:
+                    if bugs_data[task].has_key(status):
+                        print >>f, status
+                        print >>f, json.dumps(bugs_data[task][status])
+                print >>f
+        print >>f, json.dumps(bugs_data)
+        f.close()
+        SetFilePermissions(blendname+'_bugs.json')
 
-	template = loader.load('bugs.xhtml')
-	f = open(outputdir + '/' + task + '.html', 'w')
-	print >> f, template.generate(**data).render('xhtml')
+    nbugs           = {}
+    ndone           = {}
+    buglist         = {}
+    weightedsev     = {} # verbal interpretation of weighted bugs
+    weightedclass   = {} # CSS class according bug weight
+    weighttask      = {} # weighted severity as number per task
+    
+    wsev = 0  # sumarise weighted severities
+    for task in bugs_data:
+    	for status in STATES:
+            if status != 'done':
+                komma  = ''
+                for s in SEVERITIES:
+    		     if bugs_data[task][status]['severities'][s] != 0:
+    		        bugs_data[task][status]['severitysummary'] += '%s %i %s' % (komma, bugs_data[task][status]['severities'][s], s)
+    		        komma = ','
+    	if   wsev < data['assessments'][0][0]:
+    		weightedsev[task]   = _('Metapackage is in excellent shape')
+    		weightedclass[task] = data['assessments'][0][1]
+    	elif wsev < data['assessments'][1][0]:
+    		weightedsev[task]   = _('Metapackage is in very good shape')
+    		weightedclass[task] = data['assessments'][1][1]
+    	elif wsev < data['assessments'][2][0]:
+    		weightedsev[task]   = _('Metapackage is in good shape')
+    		weightedclass[task] = data['assessments'][2][1]
+    	elif wsev < data['assessments'][3][0]:
+    		weightedsev[task]   = _('Consider looking into bugs of this metapackage')
+    		weightedclass[task] = data['assessments'][3][1]
+    	elif wsev < data['assessments'][4][0]:
+    		weightedsev[task]   = _('Looking into bugs of this metapackage is recommended')
+    		weightedclass[task] = data['assessments'][4][1]
+    	else:
+    		weightedsev[task]   = _('Immediately looking into bugs of the dependencies of this metapackage is advised')
+    		weightedclass[task] = data['assessments'][5][1]
+    	weightedsev[task] += ' (%i)' % wsev
+    	weighttask[task]   = wsev
+    
+    data['headings'] = {'dependent' : _('Open bugs in dependent packages'),
+                        'suggested' : _('Open bugs in suggested packages'),
+                        'done'      : _('Done bugs')
+                       }
+    data['nobugs']   = {'dependent' : _('No open bugs in dependent packages'),
+                        'suggested' : _('No open bugs in suggested packages'),
+                        'done'      : _('No done bugs')
+                       }
+    data['cssclass'] = {'dependent' : 'bugsdependent',
+                        'suggested' : 'bugssuggested',
+                        'done'      : 'bugsdone'
+                       }
+    # FIXME: just always use 'depends' or 'dependent' etc.  This translation is just to be able to compare with old output
+    data['category'] = {'depends'   : 'dependent',
+                        'suggests'  : 'suggested',
+                        'done'      : 'done'
+                       }
+    
+    data['nbugs']           = nbugs
+    data['ndone']           = ndone
+    data['weight']          = WEIGHT
+    data['severities']      = SEVERITIES
+    data['states']          = STATES
+    data['nohomepage']      = _('Homepage not available')
+    data['novcsbrowser']    = _('Not maintained in Vcs')
+    data['vcslocation']     = _('Vcs')
+    
+    data['weighttask']      = weighttask
+    data['weightedclass']   = weightedclass
 
-	f.close()
+    for key in ('css', 'homepage', 'projecturl', 'projectname', 'logourl', 'ubuntuhome', 'projectubuntu'):
+        data[key] = config[key]
+    
+    for task in bugs_data:
+    	data['task']            = task
+    	#data['buglist']         = buglist[task]
+    	#data['weightedsev']     = weightedsev[task]
+    	#data['severitystat']    = severitystat[task]
+    
+    	template = loader.load('bugs.xhtml')
+    	f = open(outputdir + '/' + task + '.html', 'w')
+    	try:
+            print >> f, template.generate(**data).render('xhtml')
+        except UnicodeDecodeError, err:
+            fd = open('debug_'+blendname+'_bugs.json', 'w')
+            print >>fd, json.dumps(bugs_data[task])
+            fd.close()
+            SetFilePermissions(outputdir + '/' + task + '.html')
+            print err
+    
+    	f.close()
+        SetFilePermissions(outputdir + '/' + task + '.html')
+    
+    template = loader.load('bugs_idx.xhtml')
+    outputfile = outputdir + '/index.html'
+    try:
+    	os.unlink(outputfile)
+    except: # simply continue if file does not exist
+    	pass
+    f = open(outputfile, 'w')
+    print >> f, template.generate(**data).render('xhtml')
+    f.close()
+    SetFilePermissions(outputfile)
 
-template = loader.load('bugs_idx.xhtml')
-outputfile = outputdir + '/index.html'
-try:
-	os.unlink(outputfile)
-except: # simply continue if file does not exist
-	pass
-f = open(outputfile, 'w')
-print >> f, template.generate(**data).render('xhtml')
-f.close()
+if __name__ == '__main__':
+    main()
diff --git a/webtools/bugs_udd.py b/webtools/bugs_udd.py
deleted file mode 100755
index 9bfeeae..0000000
--- a/webtools/bugs_udd.py
+++ /dev/null
@@ -1,484 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013: Andreas Tille <tille at debian.org>
-# License: GPL
-
-#PORT=5441
-UDDPORT=5452
-PORT=UDDPORT
-DEFAULTPORT=5432
-
-SLOWQUERYREPORTLIMIT=30
-
-debug=0
-
-from sys import argv, stderr, exit
-import os
-import psycopg2
-import json
-import re
-import time
-from datetime import datetime
-from email.Utils import formatdate
-import email.Utils
-import gettext
-
-from genshi.template import TemplateLoader
-from genshi import Markup
-from genshi.template.eval import UndefinedError
-
-from blendsunicode   import to_unicode
-from blendstasktools import ReadConfig, RowDictionaries, CheckOrCreateOutputDir, SetFilePermissions
-from blendsmarkdown  import MarkupString
-
-###########################################################################################
-# Define several prepared statements to query UDD
-try:
-  conn = psycopg2.connect(host="localhost",port=PORT,user="guest",database="udd")
-except psycopg2.OperationalError, err:
-  try:
-    conn = psycopg2.connect("service=udd")
-  except psycopg2.OperationalError, err:
-    # logger not known at this state: logger.warning
-    print >>stderr, "Service=udd seems not to be installed on this host.\tMessage: %s" % (str(err))
-    try:
-        conn = psycopg2.connect(host="localhost",port=DEFAULTPORT,user="guest",database="udd")
-    except psycopg2.OperationalError:
-	# Hmmm, I observed a really strange behaviour on one of my machines where connecting to
-	# localhost does not work but 127.0.0.1 works fine.  No idea why ... but this should
-	# do the trick for the moment
-	conn = psycopg2.connect(host="127.0.0.1",port=DEFAULTPORT,user="guest",database="udd")
-
-curs = conn.cursor()
-# uddlog = open('logs/uddquery.log', 'w')
-
-def _execute_udd_query(query):
-    try:
-        t = time.time()
-        curs.execute(query)
-        elapsed_time = time.time() - t
-        if elapsed_time > SLOWQUERYREPORTLIMIT: # report what query took longer than SLOWQUERYREPORTLIMIT seconds
-            print "Time: %s\nQuery: %s" % (str(elapsed_time), query)
-    except psycopg2.ProgrammingError, err:
-        print >>stderr, "Problem with query\n%s" % (query)
-        print >>stderr, err
-        exit(-1)
-    except psycopg2.DataError, err:
-        print >>stderr, "%s; query was\n%s" % (err, query)
-
-
-def main():
-
-    if len(argv) <= 1:
-        print >>stderr, "Usage: %s <Blend name>" % argv[0]
-        exit(-1)
-
-    blendname = argv[1]
-    config = ReadConfig(blendname)
-
-    # Metadata of packages that might have bugs
-    query = """PREPARE query_bug_packages (text) AS
-      SELECT distinct sources.source, task, CASE WHEN (tasks.dependency = 'd' OR tasks.dependency = 'r') AND component = 'main' AND experimental_flag > 0 THEN 'depends' ELSE 'suggests' END AS status,
-                      homepage, CASE WHEN vcs_browser IS NULL THEN '#' ELSE vcs_browser END AS vcs_browser, maintainer
-        FROM (
-          SELECT s.source, b.component, s.homepage, s.vcs_browser, s.maintainer, s.version, row_number() OVER (PARTITION BY s.source ORDER BY s.version DESC)
-            FROM blends_dependencies b
-            JOIN packages p ON p.package = b.package
-            JOIN bugs bu    ON bu.source = p.source
-            JOIN sources s  ON s.source  = p.source
-            WHERE blend = $1 AND b.distribution = 'debian'
-        ) sources
-        -- check status of dependency relation because only suggested packages are less important for bugs sentinel
-        LEFT OUTER JOIN (
-          SELECT source, task, dependency FROM (
-            SELECT p.source, b.task, bdp.dependency, row_number() OVER (PARTITION BY p.source, b.task ORDER BY bdp.priority)
-              FROM packages p
-              JOIN blends_dependencies b ON b.package = p.package
-              JOIN sources s ON p.source = s.source AND p.release = s.release
-              JOIN blends_dependencies_priorities bdp ON b.dependency = bdp.dependency
-              WHERE b.blend = $1
-          ) tmp
-          WHERE row_number = 1
-        ) tasks ON sources.source = tasks.source
-        -- Check, whether a package is in experimental only which makes it less important for bugs sentinel
-        LEFT OUTER JOIN (
-          SELECT source, MAX(sort) AS experimental_flag FROM sources s
-            JOIN releases r ON s.release = r.release
-          GROUP BY source
-        ) exp ON sources.source = exp.source
-        WHERE row_number = 1
-        ORDER BY source;
-    """
-    _execute_udd_query(query)
-
-    # Actual bugs in packages of Blends dependencies
-    query = """PREPARE query_bugs (text) AS
-      SELECT source, bu.id, title, severity, status, done_by, tags FROM (
-        SELECT distinct bu.source, bu.id, bu.title, bu.severity, bu.status, bu.done AS done_by
-          FROM blends_dependencies b
-          JOIN packages p ON p.package = b.package
-          JOIN bugs bu    ON bu.source = p.source
-          WHERE blend = $1 AND b.distribution = 'debian'
-        ) bu
-        LEFT OUTER JOIN (
-          SELECT id, array_agg(tag) AS tags FROM bugs_tags GROUP BY id
-        ) bt ON bu.id = bt.id
-        ORDER BY source, bu.id;
-    """
-    _execute_udd_query(query)
-    
-    # What tasks are involved
-    query = """PREPARE query_get_tasks (text) AS
-      SELECT task, title, description, long_description FROM blends_tasks WHERE blend = $1 ORDER BY task;
-    """
-    _execute_udd_query(query)
-
-    STATES = ['depends', 'suggests', 'done']
-    SEVERITIES = ('critical', 'grave', 'serious', 'important', 'normal', 'minor', 'wishlist')
-
-    # Sense of weight: We want to find a measure how much care a metapackage needs.
-    # So we build the weighted sums of bugs and define limits for the status
-    # The weights below are used for suggested packages.  In case a package has
-    # a stronger dependency (Depends, Recommends) the weight is multiplied by 3
-    WEIGHT = { 'critical'  : 10,
-               'grave'     : 10,
-               'serious'   : 10,
-               'important' :  5,
-               'normal'    :  3,
-               'minor'     :  1,
-               'wishlist'  :  0
-             }
-    BAD          = 100 # if weighted bug sum >= BAD, the meta package is in a bad shape
-                       # Dependent packages might have 3 or more 5 RC bugs
-    PASS         =  70 # this deserves a look - potentially two RC bugs in dependent packages
-    SATISFACTORY =  50 # consider looking at this
-    GOOD         =  30 # at least no RC bug in a dependent package
-    VERYGOOD     =  10 # nothing burning
-    EXCELLENT    =   5 # There is no real need to look at this meta package
-
-    # initialise bugs_data dictionary for all tasks
-    _execute_udd_query( "EXECUTE query_get_tasks('%s')" % blendname)
-    bugs_data = {}
-    if curs.rowcount > 0:
-        for t in RowDictionaries(curs):
-            task = t['task']
-            bugs_data[task] = {}
-            bugs_data[task]['title']		= t['title']
-            bugs_data[task]['description']	= t['description']
-            bugs_data[task]['long_description']	= to_unicode(t['long_description'])
-            bugs_data[task]['nopenbugs']	= 0
-            bugs_data[task]['ndonebugs']	= 0
-            bugs_data[task]['weighttask']	= 0
-            for status in STATES:
-                bugs_data[task][status + '_l']     = [] # enable sorting
-                bugs_data[task][status]            = {}
-                bugs_data[task][status]['sources'] = []
-                if status != 'done':
-                    bugs_data[task][status]['severitysummary'] = '' # string listing number of bugs in different severity / dependency classes
-                    bugs_data[task][status]['severities'] = {}
-                    for s in SEVERITIES:
-                        bugs_data[task][status]['severities'][s] = 0
-    else:
-        print >>stderr, "No tasks metadata received for Blend", blendname
-        exit(1)
-
-    # Fetch bugs of all Blends dependencies and store them in a dictionary
-    _execute_udd_query( "EXECUTE query_bugs('%s')" % blendname)
-    bugs = {}
-    if curs.rowcount > 0:
-        for bug in RowDictionaries(curs):
-            if not bugs.has_key(bug['source']):
-                bugs[bug['source']] = {}
-                bugs[bug['source']]['severities'] = {}
-                for s in SEVERITIES:
-                    bugs[bug['source']]['severities'][s] = 0
-                bugs[bug['source']]['nopenbugs'] = 0
-                bugs[bug['source']]['ndonebugs'] = 0
-                bugs[bug['source']]['open'] = []
-                bugs[bug['source']]['done'] = []
-            b = {}
-            for k in bug.keys():
-                if k in ('source', 'status') :
-                    continue
-                if k == 'title':
-                    b[k] = to_unicode(bug[k])
-                elif k == 'tags':
-                    komma = ''
-                    b['tags'] = ''
-                    if bug[k]:
-                        for tag in bug[k]:
-                           b['tags'] += komma + tag
-                           komma      = ', '
-                else:
-                    b[k] = bug[k]
-            if bug['status'] == 'done':
-                bugs[bug['source']]['done'].append(b)
-                bugs[bug['source']]['ndonebugs'] += 1
-            else:
-                bugs[bug['source']]['open'].append(b)
-                bugs[bug['source']]['nopenbugs'] += 1
-                bugs[bug['source']]['severities'][bug['severity']] += 1
-    else:
-        print >>stderr, "No bug data received for Blend", blendname
-        exit(1)
-
-    # Merge metadata of packages and bugs together in bugs_data dictionary, also do statistics about bugs
-    _execute_udd_query( "EXECUTE query_bug_packages('%s')" % blendname)
-    if curs.rowcount > 0:
-        for pkg in RowDictionaries(curs):
-                task = pkg['task']
-                sources = {}
-                sources['source']      = pkg['source']
-                sources['homepage']    = pkg['homepage']
-                sources['vcs_browser'] = pkg['vcs_browser']
-                (_name, _url) = email.Utils.parseaddr(pkg['maintainer'])
-                sources['maintainer_email'] = _url
-                sources['maintainer_name']  = to_unicode(_name)
-                sources['maintainer']  = MarkupString('<a href="mailto:%s">%s</a>' % (_url, to_unicode(_name)), pkg['source'], 'maintainer')
-                if pkg['status'] == 'depends':
-                    sources['bugs'] = bugs[pkg['source']]['open']
-                    bugs_data[task][pkg['status']+'_l'].append(pkg['source'])
-                    for s in SEVERITIES:
-                        bugs_data[task][pkg['status']]['severities'][s] += bugs[pkg['source']]['severities'][s]
-                        bugs_data[task]['weighttask'] += 3 * WEIGHT[s] * bugs[pkg['source']]['severities'][s]
-                elif pkg['status'] == 'suggests':
-                    sources['bugs'] = bugs[pkg['source']]['open']
-                    bugs_data[task][pkg['status']+'_l'].append(pkg['source'])
-                    for s in SEVERITIES:
-                        bugs_data[task][pkg['status']]['severities'][s] += bugs[pkg['source']]['severities'][s]
-                        bugs_data[task]['weighttask'] += 1 * WEIGHT[s] * bugs[pkg['source']]['severities'][s]
-                else:
-                    print >>stderr, "%s: Wrong status %s in task %s for source %s" % (blendname, pkg['status'], task, pkg['source'])
-                    exit(1)
-                bugs_data[task][pkg['status']]['sources'].append(sources)
-                bugs_data[task]['nopenbugs'] += bugs[pkg['source']]['nopenbugs']
-                bugs_data[task]['ndonebugs'] += bugs[pkg['source']]['ndonebugs']
-                if bugs[pkg['source']]['done']:
-                    sources = {}
-                    sources['source']      = pkg['source']
-                    sources['homepage']    = pkg['homepage']
-                    sources['vcs_browser'] = pkg['vcs_browser']
-                    (_name, _url) = email.Utils.parseaddr(pkg['maintainer'])
-                    sources['maintainer_email'] = _url
-                    sources['maintainer_name']  = to_unicode(_name)
-                    sources['maintainer']  = MarkupString('<a href="mailto:%s">%s</a>' % (_url, to_unicode(_name)), pkg['source'], 'maintainer')
-                    sources['bugs']        = bugs[pkg['source']]['done']
-                    bugs_data[task]['done_l'].append(pkg['source'])
-                    bugs_data[task]['done']['sources'].append(sources)
-    else:
-        print >>stderr, "No information about buggy packages received for Blend", blendname
-        exit(1)
-
-    # Define directories used
-    current_dir  = os.path.dirname(__file__)
-    # locale_dir   = os.path.join(current_dir, 'locale')
-    template_dir = os.path.join(current_dir, 'templates')
-    
-    # initialize gensi
-    loader = TemplateLoader([template_dir], auto_reload=True)
-    
-    outputdir = CheckOrCreateOutputDir(config['outputdir'],'bugs_udd') # FIXME: as long as we are not finished use different dir
-    if outputdir == None:
-            exit(-1)
-    
-    t = datetime.now()
-    
-    # Initialize i18n
-    domain = 'blends-webtools'
-    gettext.install(domain)
-
-    data={}
-    data['projectname'] = blendname
-    data['bugs_data']   = bugs_data
-    if config.has_key('advertising') and config['advertising'] != None:
-        # we have to remove the gettext _() call which was inserted into the config
-        # file to enable easy input for config file editors - but the call has to
-        # be made explicitely in the python code
-        advertising = re.sub('_\(\W(.+)\W\)', '\\1', config['advertising'])
-        # gettext needs to escape '"' thus we need to remove the escape character '\'
-        data['projectadvertising'] = Markup(to_unicode(re.sub('\\\\"', '"', advertising)))
-    else:
-        data['projectadvertising'] = None
-
-    data['summary']           = to_unicode(_('Summary'))
-    data['idxsummary']        = to_unicode(_("""A %sDebian Pure Blend%s is a Debian internal project which assembles
-a set of packages that might help users to solve certain tasks of their work.  The list on
-the right shows the tasks of %s.""" ) \
-                                      % ('<a href="http://blends.alioth.debian.org/blends/">', '</a>', data['projectname']))
-    data['idxsummary']        = Markup(to_unicode(data['idxsummary']))
-
-    t = datetime.now()
-    data['lang']              = 'en'
-    data['othertasks']        = _("Links to other tasks")
-    data['taskslink']         = _("Tasks")
-    data['bugslink']          = _("Tasks overview")
-    data['legend']            = _("Legend")
-    data['bugsoftask']        = _("Bugs of task")
-    data['totalbugs']         = _("Total bugs")
-    data['openbugs']          = _("Open bugs")
-    data['fixedbugs']         = _("Fixed bugs")
-    data['summary']           = _('Summary')
-    data['bugssummary']       = _("""A %sDebian Pure Blend%s is a Debian internal project which assembles
-    a set of packages that might help users to solve certain tasks of their work.  This page should be helpful
-    to track down the bugs of packages that are interesting for the %s project to enable developers a quick
-    overview about possible problems.""" ) \
-                                          % ('<a href="http://blends.alioth.debian.org/blends/">', '</a>', data['projectname'])
-    data['bugssummary']        = Markup(data['bugssummary'])
-    data['gtstrBugsPage']     = _("Bugs page")
-    data['gtstrListOfBugspages'] = _("This is a list of metapackages.  The links are leading to the respective bugs page.")
-    data['updatetimestamp']   = _('Last update:') + ' ' + formatdate(time.mktime(t.timetuple()))
-    data['weightexplanation'] = _("""To estimate the overall status of the packages in the dependencies of
-    a metapackage a weighted severity is calculated.  Done bugs are ignored and bugs in dependent and
-    recommended packages are weighted by factor three compared to suggested packages.  Release critical
-    bugs have a much larger weight than important, while the contribution of normal bugs is even smaller
-    and minor bugs have a very small weight.  Wishlist bugs are ignored in this calculation.  The resulting
-    sum is compared to some boundaries to find a verbal form.  The actual numbers need some adjustment
-    to make real sense - this evaluation method is in testing phase.""")
-    data['weightdetails']     = _("The severities of bugs are weighted as follows")
-    
-    data['assessments']     = [ (EXCELLENT,    'excellent'),
-                                (VERYGOOD,     'verygood'),
-                                (GOOD,         'good'),
-                                (SATISFACTORY, 'satisfactory'),
-                                (PASS,         'pass'),
-                                (BAD,          'bad')
-                              ]
-    
-    for task in bugs_data:
-        if bugs_data[task]['weighttask'] < data['assessments'][0][0]:
-            bugs_data[task]['weightedsev']   = _('Task is in excellent shape')
-            bugs_data[task]['weightedclass'] = data['assessments'][0][1]
-        elif bugs_data[task]['weighttask'] < data['assessments'][1][0]:
-            bugs_data[task]['weightedsev']   = _('Task is in very good shape')
-            bugs_data[task]['weightedclass'] = data['assessments'][1][1]
-        elif bugs_data[task]['weighttask'] < data['assessments'][2][0]:
-            bugs_data[task]['weightedsev']   = _('Task is in good shape')
-            bugs_data[task]['weightedclass'] = data['assessments'][2][1]
-        elif bugs_data[task]['weighttask'] < data['assessments'][3][0]:
-            bugs_data[task]['weightedsev']   = _('Consider looking into bugs of this task')
-            bugs_data[task]['weightedclass'] = data['assessments'][3][1]
-        elif bugs_data[task]['weighttask'] < data['assessments'][4][0]:
-            bugs_data[task]['weightedsev']   = _('Looking into bugs of this task is recommended')
-            bugs_data[task]['weightedclass'] = data['assessments'][4][1]
-        else:
-            bugs_data[task]['weightedsev']   = _('Immediately looking into bugs of the dependencies of this task is advised')
-            bugs_data[task]['weightedclass'] = data['assessments'][5][1]
-        bugs_data[task]['weightedsev']   +=  ' (%i)' % bugs_data[task]['weighttask']
-
-    # Debuging output in JSON file
-    if debug > 0:
-        f = open(blendname+'_bugs.json', 'w')
-        if debug > 1:
-            for task in bugs_data:
-                print >>f, "*** %s ***" % task
-                for status in STATES:
-                    if bugs_data[task].has_key(status):
-                        print >>f, status
-                        print >>f, json.dumps(bugs_data[task][status])
-                print >>f
-        print >>f, json.dumps(bugs_data)
-        f.close()
-        SetFilePermissions(blendname+'_bugs.json')
-
-    nbugs           = {}
-    ndone           = {}
-    buglist         = {}
-    weightedsev     = {} # verbal interpretation of weighted bugs
-    weightedclass   = {} # CSS class according bug weight
-    weighttask      = {} # weighted severity as number per task
-    
-    wsev = 0  # sumarise weighted severities
-    for task in bugs_data:
-    	for status in STATES:
-            if status != 'done':
-                komma  = ''
-                for s in SEVERITIES:
-    		     if bugs_data[task][status]['severities'][s] != 0:
-    		        bugs_data[task][status]['severitysummary'] += '%s %i %s' % (komma, bugs_data[task][status]['severities'][s], s)
-    		        komma = ','
-    	if   wsev < data['assessments'][0][0]:
-    		weightedsev[task]   = _('Metapackage is in excellent shape')
-    		weightedclass[task] = data['assessments'][0][1]
-    	elif wsev < data['assessments'][1][0]:
-    		weightedsev[task]   = _('Metapackage is in very good shape')
-    		weightedclass[task] = data['assessments'][1][1]
-    	elif wsev < data['assessments'][2][0]:
-    		weightedsev[task]   = _('Metapackage is in good shape')
-    		weightedclass[task] = data['assessments'][2][1]
-    	elif wsev < data['assessments'][3][0]:
-    		weightedsev[task]   = _('Consider looking into bugs of this metapackage')
-    		weightedclass[task] = data['assessments'][3][1]
-    	elif wsev < data['assessments'][4][0]:
-    		weightedsev[task]   = _('Looking into bugs of this metapackage is recommended')
-    		weightedclass[task] = data['assessments'][4][1]
-    	else:
-    		weightedsev[task]   = _('Immediately looking into bugs of the dependencies of this metapackage is advised')
-    		weightedclass[task] = data['assessments'][5][1]
-    	weightedsev[task] += ' (%i)' % wsev
-    	weighttask[task]   = wsev
-    
-    data['headings'] = {'dependent' : _('Open bugs in dependent packages'),
-                        'suggested' : _('Open bugs in suggested packages'),
-                        'done'      : _('Done bugs')
-                       }
-    data['nobugs']   = {'dependent' : _('No open bugs in dependent packages'),
-                        'suggested' : _('No open bugs in suggested packages'),
-                        'done'      : _('No done bugs')
-                       }
-    data['cssclass'] = {'dependent' : 'bugsdependent',
-                        'suggested' : 'bugssuggested',
-                        'done'      : 'bugsdone'
-                       }
-    # FIXME: just always use 'depends' or 'dependent' etc.  This translation is just to be able to compare with old output
-    data['category'] = {'depends'   : 'dependent',
-                        'suggests'  : 'suggested',
-                        'done'      : 'done'
-                       }
-    
-    data['nbugs']           = nbugs
-    data['ndone']           = ndone
-    data['weight']          = WEIGHT
-    data['severities']      = SEVERITIES
-    data['states']          = STATES
-    data['nohomepage']      = _('Homepage not available')
-    data['novcsbrowser']    = _('Not maintained in Vcs')
-    data['vcslocation']     = _('Vcs')
-    
-    data['weighttask']      = weighttask
-    data['weightedclass']   = weightedclass
-
-    for key in ('css', 'homepage', 'projecturl', 'projectname', 'logourl', 'ubuntuhome', 'projectubuntu'):
-        data[key] = config[key]
-    
-    for task in bugs_data:
-    	data['task']            = task
-    	#data['buglist']         = buglist[task]
-    	#data['weightedsev']     = weightedsev[task]
-    	#data['severitystat']    = severitystat[task]
-    
-    	template = loader.load('bugs_udd.xhtml')
-    	f = open(outputdir + '/' + task + '.html', 'w')
-    	try:
-            print >> f, template.generate(**data).render('xhtml')
-        except UnicodeDecodeError, err:
-            fd = open('debug_'+blendname+'_bugs.json', 'w')
-            print >>fd, json.dumps(bugs_data[task])
-            fd.close()
-            SetFilePermissions(outputdir + '/' + task + '.html')
-            print err
-    
-    	f.close()
-        SetFilePermissions(outputdir + '/' + task + '.html')
-    
-    template = loader.load('bugs_idx_udd.xhtml')
-    outputfile = outputdir + '/index.html'
-    try:
-    	os.unlink(outputfile)
-    except: # simply continue if file does not exist
-    	pass
-    f = open(outputfile, 'w')
-    print >> f, template.generate(**data).render('xhtml')
-    f.close()
-    SetFilePermissions(outputfile)
-
-if __name__ == '__main__':
-    main()
diff --git a/webtools/templates/bugs.xhtml b/webtools/templates/bugs.xhtml
index dde95e2..686238c 100644
--- a/webtools/templates/bugs.xhtml
+++ b/webtools/templates/bugs.xhtml
@@ -4,9 +4,9 @@
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="${lang}" lang="${lang}"
       xmlns:py="http://genshi.edgewall.org/">
 <head>
-<title>$projectname ${tasks[task].metapkg.PrintedName.capitalize()} bugs</title>
+<title>$projectname ${bugs_data[task]['title'].capitalize()} bugs</title>
 <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
-<link href="$css" type="text/css" rel="stylesheet"/>
+<link href="${css}" type="text/css" rel="stylesheet"/>
 </head>
 <body>
 <div style="text-align: center;">
@@ -26,20 +26,20 @@
 		<div class="section">
 			<div class="sectionTop"/>
 			<div class="row">
-                            $bugsofpackage
-			    <strong>${tasks[task].metapkg.pkg}</strong>
+                            $bugsoftask
+			    <strong>${task}</strong>
                         </div>
 			<div class="row">
 			    $totalbugs:
-			    <strong>${nbugs[task]+ndone[task]}</strong>
+			    <strong>${bugs_data[task]['nopenbugs']+bugs_data[task]['ndonebugs']}</strong>
                         </div>
 			<div class="row">
 			    $openbugs:
-			    <strong>${nbugs[task]}</strong>
+			    <strong>${bugs_data[task]['nopenbugs']}</strong>
                         </div>
 			<div class="row">
 			    Fixed bugs:
-			    <strong>${ndone[task]}</strong>
+			    <strong>${bugs_data[task]['ndonebugs']}</strong>
                         </div>
 		</div>
 
@@ -48,11 +48,11 @@
 			<div class="sectionTop"/>
 			<div class="row">
                             <div class="link"><a href="index.html">${bugslink}</a></div>
-                          <py:for each="t in taskskeys">
+                          <py:for each="t in sorted(bugs_data.iterkeys())">
                             <div py:choose="t">
                               <span py:when="task"
-                              class="curlink"><a href="${t}.html">${tasks[t].metapkg.PrintedName.capitalize()}</a> ${nbugs[t]} (${weighttask[t]})</span>
-                              <span py:otherwise="" class="link ${weightedclass[t]}"><a href="${t}.html">${tasks[t].metapkg.PrintedName.capitalize()}</a> ${nbugs[t]} (${weighttask[t]})</span>
+                              class="curlink"><a href="${t}.html">${bugs_data[t]['title'].capitalize()}</a> ${bugs_data[t]['nopenbugs']} (${bugs_data[t]['weighttask']})</span>
+                              <span py:otherwise="" class="link ${bugs_data[t]['weightedclass']}"><a href="${t}.html">${bugs_data[t]['title'].capitalize()}</a> ${bugs_data[t]['nopenbugs']} (${bugs_data[t]['weighttask']})</span>
                             </div>
                           </py:for>
                         </div>
@@ -67,8 +67,8 @@
                       <py:for each="s in severities">
                         <tr>
 			  <td class="severity ${s}">${s}</td>
-			  <td class="bugid ${s}">${severitystat[DEPENDENT][s]}</td>
-			  <td class="bugid ${s}">${severitystat[SUGGESTED][s]}</td>
+			  <td class="bugid ${s}">${bugs_data[task]['depends']['severities'][s]}</td>
+			  <td class="bugid ${s}">${bugs_data[task]['suggests']['severities'][s]}</td>
 			</tr>
                       </py:for>
 		    </table>
@@ -78,48 +78,48 @@
 	<td class="main">
 		<div class="pageBody">
 
-<h1>Summary bugs page of ${tasks[task].metapkg.PrintedName.capitalize()} meta package</h1>
+<h1>Summary bugs page of task ${bugs_data[task]['title'].capitalize()}</h1>
 
-<div class="severitysummary">${weightedsev}<sup>*</sup></div>
+<div class="severitysummary">${bugs_data[task]['weightedsev']}<sup>*</sup></div>
 
 <span py:choose="">
-  <span py:when="nbugs[task]+ndone[task] != 0">
-    <py:for each="cat in buglistcat">
+  <span py:when="bugs_data[task]['nopenbugs']+bugs_data[task]['ndonebugs'] != 0">
+    <py:for each="status in states">
       <span py:choose="">
-	<span py:when="buglist[cat].pkgbugs != []">
-	  <h2>${headings[cat]}</h2>
-            <div class="severitylist" py:if="severitysummary[cat] != ''">
-                ${severitysummary[cat]}
+	<span py:when="bugs_data[task][status] != {}">
+	  <h2>${headings[category[status]]}</h2>
+            <div class="severitylist" py:if="status != 'done' and bugs_data[task][status]['severitysummary'] != ''">
+                ${bugs_data[task][status]['severitysummary']}
 	    </div>
-	  <table class="${cssclass[cat]}">
-	    <py:for each="pkgbug in buglist[cat].pkgbugs">
-	      <span py:if="pkgbug.nbugs > 0">
+	  <table class="${cssclass[category[status]]}">
+	    <py:for each="pkgbug in bugs_data[task][status]['sources']">
+	      <span py:if="len(pkgbug['bugs']) > 0">
 		<tr>
 		  <td class="bugid" colspan="3">
 		    <div class="bugsheadertable">
 		      <div class="bugsheadertr">
-			<span class="bugsheaderpackagetd" id="bugsheaderpackagetd"><a href="http://packages.qa.debian.org/${pkgbug.source[0]}/${pkgbug.source}.html">${pkgbug.pkgname}</a> (${pkgbug.nbugs})</span>
-                        <span class="bugsheaderhomepagetd" id="bugsheaderhomepagetd" py:choose="pkgbug.homepage">
+			<span class="bugsheaderpackagetd" id="bugsheaderpackagetd"><a href="http://packages.qa.debian.org/${pkgbug['source'][0]}/${pkgbug['source']}.html">${pkgbug['source']}</a> (${len(pkgbug['bugs'])})</span>
+                        <span class="bugsheaderhomepagetd" id="bugsheaderhomepagetd" py:choose="pkgbug['homepage']">
                           <span py:when="'#'">${nohomepage}</span>
-                          <span py:otherwise=""><a href="$pkgbug.homepage">Homepage: ${pkgbug.homepage}</a></span>
+                          <span py:otherwise=""><a href="${pkgbug['homepage']}">Homepage: ${pkgbug['homepage']}</a></span>
 			</span>
-                        <span class="bugvcsbrowser" id="bugvcsbrowser" py:choose="pkgbug.vcsbrowser">
+                        <span class="bugvcsbrowser" id="bugvcsbrowser" py:choose="pkgbug['vcs_browser']">
                           <span py:when="'#'">${novcsbrowser}</span>
-                          <span py:otherwise=""><a href="$pkgbug.vcsbrowser">${vcslocation}</a></span>
+                          <span py:otherwise=""><a href="${pkgbug['vcs_browser']}">${vcslocation}</a></span>
 			</span>
                         <span class="bugsmaintainer" id="bugsmaintainer" py:choose="">
-                          <span py:when="pkgbug.maintainer != None">${pkgbug.maintainer}</span>
+                          <span py:when="pkgbug.has_key('maintainer_email')"><a href="mailto:${pkgbug['maintainer_email']}">${pkgbug['maintainer_name']}</a></span>
                           <span py:otherwise="">unknown maintainer</span>
 			</span>
 		      </div>
                     </div>
 		  </td>
 		</tr>
-		<py:for each="bug in pkgbug.bugs">
+		<py:for each="bug in pkgbug['bugs']">
 		  <tr>
-		    <td class="bugid ${bug.severity}"><a href="http://bugs.debian.org/${bug.bug}">${bug.bug}</a></td>
-		    <td class="summary ${bug.severity}">${bug.summary}</td>
-		    <td class="severity ${bug.severity}">${bug.tags}</td>
+		    <td class="bugid ${bug['severity']}"><a href="http://bugs.debian.org/${bug['id']}">${bug['id']}</a></td>
+		    <td class="summary ${bug['severity']}">${bug['title']}</td>
+		    <td class="severity ${bug['severity']}">${bug['tags']}</td>
 		  </tr>
 		</py:for>
 	      </span>
@@ -131,8 +131,7 @@
     </py:for>
    </span>
   <span py:otherwise=""><h2>$projectname
-  ${tasks[task].metapkg.PrintedName.capitalize()} has no known nbugs =
-  ${nbugs[task]}  ndone = ${ndone[task]}</h2></span>
+  ${bugs_data[task]['title'].capitalize()} has no known nbugs = ${bugs_data[task]['nopenbugs']} ndone = ${bugs_data[task]['ndonebugs']}</h2></span>
 </span>
 <div class="footnotecontent">
   <sup>*</sup>${weightexplanation}
diff --git a/webtools/templates/bugs_idx.xhtml b/webtools/templates/bugs_idx.xhtml
index d56ce2a..50233bf 100644
--- a/webtools/templates/bugs_idx.xhtml
+++ b/webtools/templates/bugs_idx.xhtml
@@ -48,15 +48,9 @@
 			<h1>$gtstrBugsPage</h1>
 			<p>$gtstrListOfBugspages</p>
 			<dl>
-                             <py:for each="task in taskskeys">
-                                <dt class="${weightedclass[task]}"><a href="${task}.html" name="${task}" id="${task}">${tasks[task].metapkg.PrintedName.capitalize()} - <span py:choose="">
-	           <span py:when="tasks[task].metapkg.desc.has_key(lang)">${tasks[task].metapkg.desc[lang]['short']}</span>
-	           <span py:otherwise="">${tasks[task].metapkg.desc['en']['short']}</span>
-                 </span></a> (${weighttask[task]}<sup>*</sup>)</dt>
-				<dd><span py:choose="">
-	           <span py:when="tasks[task].metapkg.desc.has_key(lang)">${tasks[task].metapkg.desc[lang]['long']}</span>
-	           <span py:otherwise="">${tasks[task].metapkg.desc['en']['long']}</span>
-                 </span></dd>
+                             <py:for each="task in sorted(bugs_data.iterkeys())">
+                                <dt class="${bugs_data[task]['weightedclass']}"><a href="${task}.html" name="${task}" id="${task}">${bugs_data[task]['title'].capitalize()} - ${bugs_data[task]['description']}</a> (${bugs_data[task]['weighttask']}<sup>*</sup>)</dt>
+				<dd>${bugs_data[task]['long_description']}</dd>
                              </py:for>
 			</dl>
 <div class="footnotecontent">
diff --git a/webtools/templates/bugs_idx_udd.xhtml b/webtools/templates/bugs_idx_udd.xhtml
deleted file mode 100644
index 50233bf..0000000
--- a/webtools/templates/bugs_idx_udd.xhtml
+++ /dev/null
@@ -1,75 +0,0 @@
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="${lang}" lang="${lang}"
-      xmlns:py="http://genshi.edgewall.org/">
-<head>
-<title>$projectname bugs</title>
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
-<link href="$css" type="text/css" rel="stylesheet"/>
-</head>
-<body>
-<div style="text-align: center;">
-<a href="$projecturl"><span py:choose="logourl">
-	           <span py:when="None">${projectname} Project</span>
-	           <span py:otherwise=""><img src="$logourl" alt="$projectname Project" height="93" /></span>
-                 </span>
-</a>
-</div>
-<div class="heading" py:if="projectadvertising">
-	<div class="tabBar" style="text-align: center;">$projectadvertising</div>
-</div>
-<table class="columns">
-<tr>
-	<td class="left">
-		<span class="section">$summary</span>
-		<div class="section">
-			<div class="sectionTop"></div>
-			<div class="row">${bugssummary}</div>
-		</div>
-		<span class="section">${legend}</span>
-		<div class="section">
-		  <div class="sectionTop"/>
-		  <div class="row">
-		    <table>
-		      <tr><th>Assessment</th><th>Limit</th></tr>
-                      <py:for each="a in assessments">
-                        <tr>
-			  <td class="${a[1]}">${a[1]}</td>
-			  <td class="${a[1]}">${a[0]}</td>
-			</tr>
-                      </py:for>
-		    </table>
-                  </div>
-		</div>
-	</td>
-	<td class="main">
-		<div class="pageBody">
-			<h1>$gtstrBugsPage</h1>
-			<p>$gtstrListOfBugspages</p>
-			<dl>
-                             <py:for each="task in sorted(bugs_data.iterkeys())">
-                                <dt class="${bugs_data[task]['weightedclass']}"><a href="${task}.html" name="${task}" id="${task}">${bugs_data[task]['title'].capitalize()} - ${bugs_data[task]['description']}</a> (${bugs_data[task]['weighttask']}<sup>*</sup>)</dt>
-				<dd>${bugs_data[task]['long_description']}</dd>
-                             </py:for>
-			</dl>
-<div class="footnotecontent">
-  <sup>*</sup>${weightexplanation}
-  <br />
-  ${weightdetails}:
-  <br />
-  <table class="footnotecontent">
-    <py:for each="s in severities">
-      <tr><td class="footnotecontent">${s}</td><td class="footnotecontent">${weight[s]}</td></tr>
-    </py:for>
-  </table>
-</div>
-		</div>
-	</td>
-</tr>
-</table>
-<div id="footer">
-  <address>${updatetimestamp}</address>
-</div>
-</body>
-</html>
diff --git a/webtools/templates/bugs_udd.xhtml b/webtools/templates/bugs_udd.xhtml
deleted file mode 100644
index 686238c..0000000
--- a/webtools/templates/bugs_udd.xhtml
+++ /dev/null
@@ -1,155 +0,0 @@
-<!DOCTYPE html
-     PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="${lang}" lang="${lang}"
-      xmlns:py="http://genshi.edgewall.org/">
-<head>
-<title>$projectname ${bugs_data[task]['title'].capitalize()} bugs</title>
-<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8"/>
-<link href="${css}" type="text/css" rel="stylesheet"/>
-</head>
-<body>
-<div style="text-align: center;">
-<a href="$projecturl"><span py:choose="logourl">
-	           <span py:when="None">${projectname} Project</span>
-	           <span py:otherwise=""><img src="$logourl" alt="$projectname Project" height="93" /></span>
-                 </span>
-</a>
-</div>
-<div class="heading" py:if="projectadvertising">
-	<div class="tabBar" style="text-align: center;">$projectadvertising</div>
-</div>
-<table class="columns">
-<tr>
-	<td class="left">
-		<span class="section">Summary</span>
-		<div class="section">
-			<div class="sectionTop"/>
-			<div class="row">
-                            $bugsoftask
-			    <strong>${task}</strong>
-                        </div>
-			<div class="row">
-			    $totalbugs:
-			    <strong>${bugs_data[task]['nopenbugs']+bugs_data[task]['ndonebugs']}</strong>
-                        </div>
-			<div class="row">
-			    $openbugs:
-			    <strong>${bugs_data[task]['nopenbugs']}</strong>
-                        </div>
-			<div class="row">
-			    Fixed bugs:
-			    <strong>${bugs_data[task]['ndonebugs']}</strong>
-                        </div>
-		</div>
-
-		<span class="section">${othertasks}</span>
-		<div class="section">
-			<div class="sectionTop"/>
-			<div class="row">
-                            <div class="link"><a href="index.html">${bugslink}</a></div>
-                          <py:for each="t in sorted(bugs_data.iterkeys())">
-                            <div py:choose="t">
-                              <span py:when="task"
-                              class="curlink"><a href="${t}.html">${bugs_data[t]['title'].capitalize()}</a> ${bugs_data[t]['nopenbugs']} (${bugs_data[t]['weighttask']})</span>
-                              <span py:otherwise="" class="link ${bugs_data[t]['weightedclass']}"><a href="${t}.html">${bugs_data[t]['title'].capitalize()}</a> ${bugs_data[t]['nopenbugs']} (${bugs_data[t]['weighttask']})</span>
-                            </div>
-                          </py:for>
-                        </div>
-		</div>
-
-		<span class="section">${legend}</span>
-		<div class="section">
-		  <div class="sectionTop"/>
-		  <div class="row">
-		    <table>
-		      <tr><th>Severity</th><th>Dependent</th><th>Suggested</th></tr>
-                      <py:for each="s in severities">
-                        <tr>
-			  <td class="severity ${s}">${s}</td>
-			  <td class="bugid ${s}">${bugs_data[task]['depends']['severities'][s]}</td>
-			  <td class="bugid ${s}">${bugs_data[task]['suggests']['severities'][s]}</td>
-			</tr>
-                      </py:for>
-		    </table>
-                  </div>
-		</div>
-	</td>
-	<td class="main">
-		<div class="pageBody">
-
-<h1>Summary bugs page of task ${bugs_data[task]['title'].capitalize()}</h1>
-
-<div class="severitysummary">${bugs_data[task]['weightedsev']}<sup>*</sup></div>
-
-<span py:choose="">
-  <span py:when="bugs_data[task]['nopenbugs']+bugs_data[task]['ndonebugs'] != 0">
-    <py:for each="status in states">
-      <span py:choose="">
-	<span py:when="bugs_data[task][status] != {}">
-	  <h2>${headings[category[status]]}</h2>
-            <div class="severitylist" py:if="status != 'done' and bugs_data[task][status]['severitysummary'] != ''">
-                ${bugs_data[task][status]['severitysummary']}
-	    </div>
-	  <table class="${cssclass[category[status]]}">
-	    <py:for each="pkgbug in bugs_data[task][status]['sources']">
-	      <span py:if="len(pkgbug['bugs']) > 0">
-		<tr>
-		  <td class="bugid" colspan="3">
-		    <div class="bugsheadertable">
-		      <div class="bugsheadertr">
-			<span class="bugsheaderpackagetd" id="bugsheaderpackagetd"><a href="http://packages.qa.debian.org/${pkgbug['source'][0]}/${pkgbug['source']}.html">${pkgbug['source']}</a> (${len(pkgbug['bugs'])})</span>
-                        <span class="bugsheaderhomepagetd" id="bugsheaderhomepagetd" py:choose="pkgbug['homepage']">
-                          <span py:when="'#'">${nohomepage}</span>
-                          <span py:otherwise=""><a href="${pkgbug['homepage']}">Homepage: ${pkgbug['homepage']}</a></span>
-			</span>
-                        <span class="bugvcsbrowser" id="bugvcsbrowser" py:choose="pkgbug['vcs_browser']">
-                          <span py:when="'#'">${novcsbrowser}</span>
-                          <span py:otherwise=""><a href="${pkgbug['vcs_browser']}">${vcslocation}</a></span>
-			</span>
-                        <span class="bugsmaintainer" id="bugsmaintainer" py:choose="">
-                          <span py:when="pkgbug.has_key('maintainer_email')"><a href="mailto:${pkgbug['maintainer_email']}">${pkgbug['maintainer_name']}</a></span>
-                          <span py:otherwise="">unknown maintainer</span>
-			</span>
-		      </div>
-                    </div>
-		  </td>
-		</tr>
-		<py:for each="bug in pkgbug['bugs']">
-		  <tr>
-		    <td class="bugid ${bug['severity']}"><a href="http://bugs.debian.org/${bug['id']}">${bug['id']}</a></td>
-		    <td class="summary ${bug['severity']}">${bug['title']}</td>
-		    <td class="severity ${bug['severity']}">${bug['tags']}</td>
-		  </tr>
-		</py:for>
-	      </span>
-	    </py:for>
-	  </table>
-	</span>
-	<span py:otherwise=""><h2>${nobugs[cat]}</h2></span>
-      </span>
-    </py:for>
-   </span>
-  <span py:otherwise=""><h2>$projectname
-  ${bugs_data[task]['title'].capitalize()} has no known nbugs = ${bugs_data[task]['nopenbugs']} ndone = ${bugs_data[task]['ndonebugs']}</h2></span>
-</span>
-<div class="footnotecontent">
-  <sup>*</sup>${weightexplanation}
-  <br />
-  ${weightdetails}:
-  <br />
-  <table class="footnotecontent">
-    <py:for each="s in severities">
-      <tr><td class="footnotecontent">${s}</td><td class="footnotecontent">${weight[s]}</td></tr>
-    </py:for>
-  </table>
-</div>
-		</div>
-	</td>
-</tr>
-</table>
-<div class="footnote">
-  <address>${updatetimestamp}</address>
-</div>
-</body>
-</html>
diff --git a/webtools/update-all b/webtools/update-all
index 0d5dccb..9c6dd7b 100755
--- a/webtools/update-all
+++ b/webtools/update-all
@@ -1,5 +1,5 @@
 #!/bin/sh
 ./update-all-tasks
 ./update-all-thermometers
-./update-all-bugs_udd
+./update-all-bugs
 [ -x /usr/local/bin/static-update-component ] && /usr/local/bin/static-update-component blends.debian.org >/dev/null 2>/dev/null
diff --git a/webtools/update-all-bugs b/webtools/update-all-bugs
index 228672b..53b534f 100755
--- a/webtools/update-all-bugs
+++ b/webtools/update-all-bugs
@@ -1,5 +1,12 @@
 #!/bin/sh
+runscript=`basename $0 | sed 's/^update-all-//'`
 mkdir -p logs
 for blend in `ls webconf/*.conf  | grep -v -e "webconf/fun\." -e rest-test | sed 's?webconf/\(.*\)\.conf?\1?'` ; do
-    ./bugs.py $blend 2> logs/${blend}_bugs.err > logs/${blend}_bugs.out
+  if [ "$blend" != "debian-edu" ] ; then
+    starttime=`date "+%s"`
+    # time
+    ./${runscript}.py $blend 2> logs/${blend}_${runscript}.err > logs/${blend}_${runscript}.out
+    endtime=`date "+%s"`
+    echo "Rendering bugs from UDD for Blend '$blend' took $((endtime-starttime)) seconds" >> logs/${blend}_${runscript}.out
+  fi
 done
diff --git a/webtools/update-all-bugs_udd b/webtools/update-all-bugs_udd
deleted file mode 100755
index 53b534f..0000000
--- a/webtools/update-all-bugs_udd
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-runscript=`basename $0 | sed 's/^update-all-//'`
-mkdir -p logs
-for blend in `ls webconf/*.conf  | grep -v -e "webconf/fun\." -e rest-test | sed 's?webconf/\(.*\)\.conf?\1?'` ; do
-  if [ "$blend" != "debian-edu" ] ; then
-    starttime=`date "+%s"`
-    # time
-    ./${runscript}.py $blend 2> logs/${blend}_${runscript}.err > logs/${blend}_${runscript}.out
-    endtime=`date "+%s"`
-    echo "Rendering bugs from UDD for Blend '$blend' took $((endtime-starttime)) seconds" >> logs/${blend}_${runscript}.out
-  fi
-done

-- 
Static and dynamic websites for Debian Pure Blends



More information about the Blends-commit mailing list