← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/remove-germinate-scripts into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-germinate-scripts into lp:launchpad.

Commit message:
Remove all germinate-related code, now moved into lp:ubuntu-archive-publishing.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/remove-germinate-scripts/+merge/222478

https://code.launchpad.net/~cjwatson/ubuntu-archive-publishing/add-germinate-scripts/+merge/222477 adds the germinate-related code from Launchpad to ubuntu-archive-publishing.  Once this has been deployed, there is no further reason to keep that code in Launchpad, and so we can remove it.

The only non-obvious thing to note here is that cron.germinate is the last remaining user of lp-query-distro.py.  It can probably be converted to get the same information from launchpadlib without too much difficulty, but I didn't do that in the initial port.  We need to keep lp-query-distro.py (another 386 LoC) in Launchpad until that's been done.
-- 
https://code.launchpad.net/~cjwatson/launchpad/remove-germinate-scripts/+merge/222478
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-germinate-scripts into lp:launchpad.
=== removed file 'cronscripts/generate-extra-overrides.py'
--- cronscripts/generate-extra-overrides.py	2011-12-04 15:14:23 +0000
+++ cronscripts/generate-extra-overrides.py	1970-01-01 00:00:00 +0000
@@ -1,18 +0,0 @@
-#!/usr/bin/python -S
-#
-# Copyright 2011 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Generate extra overrides using Germinate."""
-
-import _pythonpath
-
-from lp.archivepublisher.scripts.generate_extra_overrides import (
-    GenerateExtraOverrides,
-    )
-
-
-if __name__ == '__main__':
-    script = GenerateExtraOverrides(
-        "generate-extra-overrides", dbuser='generate_extra_overrides')
-    script.lock_and_run()

=== removed file 'cronscripts/publishing/cron.germinate'
--- cronscripts/publishing/cron.germinate	2014-05-20 11:59:54 +0000
+++ cronscripts/publishing/cron.germinate	1970-01-01 00:00:00 +0000
@@ -1,61 +0,0 @@
-#! /bin/sh
-#
-# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-set -e
-set -u
-
-ARCHIVEROOT=${TEST_ARCHIVEROOT:-/srv/launchpad.net/ubuntu-archive/ubuntu}
-MISCROOT=$ARCHIVEROOT/../ubuntu-misc
-LOCKROOT=$ARCHIVEROOT/..
-GERMINATEROOT=$ARCHIVEROOT/../ubuntu-germinate
-
-LAUNCHPADROOT=${TEST_LAUNCHPADROOT:-`dirname $0`/../..}
-GENERATE=$LAUNCHPADROOT/cronscripts/generate-extra-overrides.py
-MAINTAINCE_CHECK=$LAUNCHPADROOT/cronscripts/publishing/maintenance-check.py
-
-FLAVOURS="ubuntu kubuntu kubuntu-active edubuntu xubuntu mythbuntu lubuntu"
-FLAVOURS="$FLAVOURS ubuntustudio ubuntu-gnome ubuntu-touch"
-
-## Check to see if another germinate run is in progress
-
-LOCKFILE=$LOCKROOT/cron.germinate.lock
-if lockfile -! -l 43200 -r 0 "${LOCKFILE}"; then
-  echo Another cron.germinate appears to be running
-  exit 1
-fi
-
-cleanup () {
-  rm -f "$LOCKFILE"
-}
-
-trap cleanup EXIT
-
-cd $GERMINATEROOT
-
-$GENERATE -d ubuntu $FLAVOURS
-
-# Now generate the Supported extra overrides for all supported distros.
-SUITES=`$LAUNCHPADROOT/scripts/ftpmaster-tools/lp-query-distro.py supported`
-for supported_suite in $SUITES; do
-    echo -n "Running maintenance-check for $supported_suite... "
-    # The support timeframe information is stored here
-    SUPPORTED="$MISCROOT/more-extra.override.$supported_suite.main.supported"
-    # This is the target override file that contains germinate plus
-    # support info.
-    TARGET="$MISCROOT/more-extra.override.$supported_suite.main"
-    # Debug/Log information
-    LOG="_maintenance-check.$supported_suite.stderr"
-    if $MAINTAINCE_CHECK $supported_suite > $SUPPORTED 2> $LOG; then
-        # The target file may be missing on the server and the script should
-        # not fail if that is the case.
-        touch $TARGET
-        # Remove old "Supported" info from extra-overrides as it may be
-        # stale now and we replace it with fresh content below.
-        sed /"^.* Supported"/d $TARGET > ${TARGET}.new
-        cat $SUPPORTED >> ${TARGET}.new
-        mv ${TARGET}.new $TARGET
-    fi
-    echo " done"
-done

=== removed file 'cronscripts/publishing/maintenance-check.py'
--- cronscripts/publishing/maintenance-check.py	2014-03-18 17:30:51 +0000
+++ cronscripts/publishing/maintenance-check.py	1970-01-01 00:00:00 +0000
@@ -1,529 +0,0 @@
-#!/usr/bin/python
-#
-# python port of the nice maintainace-check script by  Nick Barcet
-#
-
-import logging
-from optparse import OptionParser
-import os
-import sys
-import urllib2
-import urlparse
-
-import apt
-import apt_pkg
-
-
-class UbuntuMaintenance(object):
-    """ Represents the support timeframe for a regular ubuntu release """
-
-    # architectures that are full supported (including LTS time)
-    PRIMARY_ARCHES = [
-        "i386",
-        "amd64",
-        ]
-
-    # architectures we support (but not for LTS time)
-    SUPPORTED_ARCHES = PRIMARY_ARCHES + [
-        "armel",
-        "armhf",
-        "arm64",
-        "ppc64el",
-        ]
-
-    # what defines the seeds is documented in wiki.ubuntu.com/SeedManagement
-    SERVER_SEEDS = [
-        "server-ship",
-        "supported-server",
-        ]
-    DESKTOP_SEEDS = [
-        "ship",
-        "supported-desktop",
-        "supported-desktop-extra",
-        ]
-    SUPPORTED_SEEDS = ["all"]
-
-    # normal support timeframe
-    # time, seeds
-    SUPPORT_TIMEFRAME = [
-        ("9m", SUPPORTED_SEEDS),
-        ]
-
-    # shorter than normal support timeframe
-    # time, seed
-    SUPPORT_TIMEFRAME_SHORT = [
-        ]
-
-    # distro names that we check the seeds for
-    DISTRO_NAMES = [
-        "ubuntu",
-        ]
-
-    # distro names for shorter than default support cycles
-    DISTRO_NAMES_SHORT = [
-        ]
-
-
-# This is fun! We have a bunch of cases for 10.04 LTS
-#
-#  - distro "ubuntu" follows SUPPORT_TIMEFRAME_LTS but only for
-#    amd64/i386
-#  - distros "kubuntu", "edubuntu" and "netbook" need to be
-#    considered *but* only follow SUPPORT_TIMEFRAME
-#  - anything that is in armel follows SUPPORT_TIMEFRAME
-#
-class LucidUbuntuMaintenance(UbuntuMaintenance):
-    """ Represents the support timeframe for a 10.04 (lucid) LTS release,
-        the exact rules differ from LTS release to LTS release
-    """
-
-    # lts support timeframe, order is important, least supported must be last
-    # time, seeds
-    SUPPORT_TIMEFRAME = [
-        ("5y",  UbuntuMaintenance.SERVER_SEEDS),
-        ("3y",  UbuntuMaintenance.DESKTOP_SEEDS),
-        ("18m", UbuntuMaintenance.SUPPORTED_SEEDS),
-        ]
-
-    # on a LTS this is significant, it defines what names get LTS support
-    DISTRO_NAMES = [
-        "ubuntu",
-        "kubuntu",
-        ]
-
-
-class PreciseUbuntuMaintenance(UbuntuMaintenance):
-    """ The support timeframe for the 12.04 (precise) LTS release.
-        This changes the timeframe for desktop packages from 3y to 5y
-    """
-
-    # lts support timeframe, order is important, least supported must be last
-    # time, seeds
-    SUPPORT_TIMEFRAME = [
-        ("5y", UbuntuMaintenance.SERVER_SEEDS),
-        ("5y", UbuntuMaintenance.DESKTOP_SEEDS),
-        ("18m", UbuntuMaintenance.SUPPORTED_SEEDS),
-        ]
-
-    # on a LTS this is significant, it defines what names get LTS support
-    DISTRO_NAMES = [
-        "ubuntu",
-        "kubuntu",
-        ]
-
-
-class QuantalUbuntuMaintenance(UbuntuMaintenance):
-
-    SUPPORT_TIMEFRAME = [
-        ("18m", UbuntuMaintenance.SUPPORTED_SEEDS),
-        ]
-
-
-OneiricUbuntuMaintenance = QuantalUbuntuMaintenance
-
-
-class TrustyUbuntuMaintenance(UbuntuMaintenance):
-    """ The support timeframe for the 14.04 (trusty) LTS release.
-        This changes the timeframe for desktop packages from 3y to 5y
-    """
-
-    # lts support timeframe, order is important, least supported must be last
-    # time, seeds
-    SUPPORT_TIMEFRAME = [
-        ("5y", UbuntuMaintenance.SERVER_SEEDS),
-        ("5y", UbuntuMaintenance.DESKTOP_SEEDS),
-        ("9m", UbuntuMaintenance.SUPPORTED_SEEDS),
-        ]
-
-    SUPPORT_TIMEFRAME_SHORT = [
-        ("3y", UbuntuMaintenance.SERVER_SEEDS),
-        ("3y", UbuntuMaintenance.DESKTOP_SEEDS),
-        ("9m", UbuntuMaintenance.SUPPORTED_SEEDS),
-        ]
-        
-    # on a LTS this is significant, it defines what names get LTS support
-    #
-    # Kylin is not in this list, becuase it's not seed managed =/,
-    # it is LTS however as per 2014-03-17 Ubuntu TechBoard meeting
-    DISTRO_NAMES = [
-        "ubuntu",
-        "kubuntu",
-        "edubuntu",
-        ]
-
-    DISTRO_NAMES_SHORT = [
-        "ubuntu-gnome",
-        "xubuntu",
-        "mythbuntu",
-        "ubuntustudio",
-        "lubuntu",
-        ]
-
-
-# Names of the distribution releases that are not supported by this
-# tool. All later versions are supported.
-UNSUPPORTED_DISTRO_RELEASED = [
-    "dapper",
-    "edgy",
-    "feisty",
-    "gutsy",
-    "hardy",
-    "intrepid",
-    "jaunty",
-    "karmic",
-    ]
-
-
-# germinate output base directory
-BASE_URL = os.environ.get(
-    "MAINTENANCE_CHECK_BASE_URL",
-    "http://people.canonical.com/~ubuntu-archive/germinate-output/";)
-
-# hints dir url, hints file is "$distro.hints" by default
-# (e.g. lucid.hints)
-HINTS_DIR_URL = os.environ.get(
-    "MAINTENANCE_CHECK_HINTS_DIR_URL",
-    "http://people.canonical.com/";
-        "~ubuntu-archive/seeds/platform.%s/SUPPORTED_HINTS")
-
-# we need the archive root to parse the Sources file to support
-# by-source hints
-ARCHIVE_ROOT = os.environ.get(
-    "MAINTENANCE_CHECK_ARCHIVE_ROOT", "http://archive.ubuntu.com/ubuntu";)
-
-# support timeframe tag used in the Packages file
-SUPPORT_TAG = "Supported"
-
-
-def get_binaries_for_source_pkg(srcname):
-    """ Return all binary package names for the given source package name.
-
-    :param srcname: The source package name.
-    :return: A list of binary package names.
-    """
-    pkgnames = set()
-    recs = apt_pkg.SourceRecords()
-    while recs.lookup(srcname):
-        for binary in recs.binaries:
-            pkgnames.add(binary)
-    return pkgnames
-
-
-def expand_src_pkgname(pkgname):
-    """ Expand a package name if it is prefixed with src.
-
-    If the package name is prefixed with src it will be expanded
-    to a list of binary package names. Otherwise the original
-    package name will be returned.
-
-    :param pkgname: The package name (that may include src:prefix).
-    :return: A list of binary package names (the list may be one element
-             long).
-    """
-    if not pkgname.startswith("src:"):
-        return [pkgname]
-    return get_binaries_for_source_pkg(pkgname.split("src:")[1])
-
-
-def create_and_update_deb_src_source_list(distroseries):
-    """ Create sources.list and update cache.
-
-    This creates a sources.list file with deb-src entries for a given
-    distroseries and apt.Cache.update() to make sure the data is up-to-date.
-    :param distro: The code name of the distribution series (e.g. lucid).
-    :return: None
-    :raises: IOError: When cache update fails.
-    """
-    # apt root dir
-    rootdir = "./aptroot.%s" % distroseries
-    sources_list_dir = os.path.join(rootdir, "etc", "apt")
-    if not os.path.exists(sources_list_dir):
-        os.makedirs(sources_list_dir)
-    sources_list = open(os.path.join(sources_list_dir, "sources.list"), "w")
-    for pocket in [
-        "%s" % distroseries,
-        "%s-updates" % distroseries,
-        "%s-security" % distroseries]:
-        sources_list.write(
-            "deb-src %s %s main restricted\n" % (
-                ARCHIVE_ROOT, pocket))
-        sources_list.write(
-            "deb %s %s main restricted\n" % (
-                ARCHIVE_ROOT, pocket))
-    sources_list.close()
-    # create required dirs/files for apt.Cache(rootdir) to work on older
-    # versions of python-apt. once lucid is used it can be removed
-    for d in ["var/lib/dpkg",
-              "var/cache/apt/archives/partial",
-              "var/lib/apt/lists/partial"]:
-        if not os.path.exists(os.path.join(rootdir, d)):
-            os.makedirs(os.path.join(rootdir, d))
-    if not os.path.exists(os.path.join(rootdir, "var/lib/dpkg/status")):
-        open(os.path.join(rootdir, "var/lib/dpkg/status"), "w")
-    # open cache with our just prepared rootdir
-    cache = apt.Cache(rootdir=rootdir)
-    try:
-        cache.update()
-    except SystemError:
-        logging.exception("cache.update() failed")
-
-
-def get_structure(distroname, version):
-    """ Get structure file conent for named distro and distro version.
-
-    :param name: Name of the distribution (e.g. kubuntu, ubuntu, xubuntu).
-    :param version: Code name of the distribution version (e.g. lucid).
-    :return: List of strings with the structure file content
-    """
-    f = urllib2.urlopen("%s/%s.%s/structure" % (
-            BASE_URL, distroname, version))
-    structure = f.readlines()
-    f.close()
-    return structure
-
-
-def expand_seeds(structure, seedname):
-    """Expand seed by its dependencies using the strucure file.
-
-    :param structure: The content of the STRUCTURE file as string list.
-    :param seedname: The name of the seed as string that needs to be expanded.
-    :return: A set() for the seed dependencies (excluding the original
-        seedname).
-    """
-    seeds = []
-    for line in structure:
-        if line.startswith("%s:" % seedname):
-            seeds += line.split(":")[1].split()
-            for seed in seeds:
-                seeds += expand_seeds(structure, seed)
-    return set(seeds)
-
-
-def get_packages_for_seeds(name, distro, seeds):
-    """
-    Get packages for the given name (e.g. ubuntu) and distro release
-    (e.g. lucid) that are in the given list of seeds
-    returns a set() of package names.
-    """
-    pkgs_in_seeds = {}
-    for seed in seeds:
-        pkgs_in_seeds[seed] = set()
-        seedurl = "%s/%s.%s/%s" % (BASE_URL, name, distro, seed)
-        logging.debug("looking for '%s'", seedurl)
-        try:
-            f = urllib2.urlopen(seedurl)
-            for line in f:
-                # Ignore lines that are not package names (headers etc).
-                if line[0] < 'a' or line[0] > 'z':
-                    continue
-                # Each line contains these fields:
-                # (package, source, why, maintainer, size, inst-size)
-                if options.source_packages:
-                    pkgname = line.split("|")[1]
-                else:
-                    pkgname = line.split("|")[0]
-                pkgs_in_seeds[seed].add(pkgname.strip())
-            f.close()
-        except Exception as e:
-            logging.error("seed %s failed (%s)" % (seedurl, e))
-    return pkgs_in_seeds
-
-
-def what_seeds(pkgname, seeds):
-    in_seeds = set()
-    for s in seeds:
-        if pkgname in seeds[s]:
-            in_seeds.add(s)
-    return in_seeds
-
-
-def compare_support_level(x, y):
-    """
-    compare two support level strings of the form 18m, 3y etc
-    :parm x: the first support level
-    :parm y: the second support level
-    :return: negative if x < y, zero if x==y, positive if x > y
-    """
-
-    def support_to_int(support_time):
-        """
-        helper that takes a support time string and converts it to
-        a integer for cmp()
-        """
-        # allow strings like "5y (kubuntu-common)
-        x = support_time.split()[0]
-        if x.endswith("y"):
-            return 12 * int(x[0:-1])
-        elif x.endswith("m"):
-            return int(x[0:-1])
-        else:
-            raise ValueError("support time '%s' has to end with y or m" % x)
-    return cmp(support_to_int(x), support_to_int(y))
-
-
-def get_packages_support_time(structure, name, pkg_support_time,
-                              support_timeframe_list):
-    """
-    input a structure file and a list of pair<timeframe, seedlist>
-    return a dict of pkgnames -> support timeframe string
-    """
-    for (timeframe, seedlist) in support_timeframe_list:
-        expanded = set()
-        for s in seedlist:
-            expanded.add(s)
-            expanded |= expand_seeds(structure, s)
-        pkgs_in_seeds = get_packages_for_seeds(name, distro, expanded)
-        for seed in pkgs_in_seeds:
-            for pkg in pkgs_in_seeds[seed]:
-                if not pkg in pkg_support_time:
-                    pkg_support_time[pkg] = timeframe
-                else:
-                    old_timeframe = pkg_support_time[pkg]
-                    if compare_support_level(old_timeframe, timeframe) < 0:
-                        logging.debug("overwriting %s from %s to %s" % (
-                                pkg, old_timeframe, timeframe))
-                        pkg_support_time[pkg] = timeframe
-                if options.with_seeds:
-                    pkg_support_time[pkg] += " (%s)" % ", ".join(
-                        what_seeds(pkg, pkgs_in_seeds))
-
-    return pkg_support_time
-
-
-if __name__ == "__main__":
-    parser = OptionParser()
-    parser.add_option("--with-seeds", "", default=False,
-                      action="store_true",
-                      help="add seed(s) of the package that are responsible "
-                           "for the maintaince time")
-    parser.add_option("--source-packages", "", default=False,
-                      action="store_true",
-                      help="show as source pkgs")
-    parser.add_option("--hints-file", "", default=None,
-                      help="use diffenrt use hints file location")
-    (options, args) = parser.parse_args()
-
-    # init
-    if len(args) > 0:
-        distro = args[0]
-        if distro in UNSUPPORTED_DISTRO_RELEASED:
-            logging.error("only lucid or later is supported")
-            sys.exit(1)
-    else:
-        distro = "lucid"
-
-    # maintenance class to use
-    klass = globals().get("%sUbuntuMaintenance" % distro.capitalize())
-    if klass is None:
-        klass = UbuntuMaintenance
-    ubuntu_maintenance = klass()
-
-    # make sure our deb-src information is up-to-date
-    create_and_update_deb_src_source_list(distro)
-
-    if options.hints_file:
-        hints_file = options.hints_file
-        (schema, netloc, path, query, fragment) = urlparse.urlsplit(
-            hints_file)
-        if not schema:
-            hints_file = "file:%s" % path
-    else:
-        hints_file = HINTS_DIR_URL % distro
-
-    # go over the distros we need to check
-    pkg_support_time = {}
-    for names, support_timeframe in (
-            (ubuntu_maintenance.DISTRO_NAMES_SHORT, ubuntu_maintenance.SUPPORT_TIMEFRAME_SHORT),
-            (ubuntu_maintenance.DISTRO_NAMES, ubuntu_maintenance.SUPPORT_TIMEFRAME),
-            ):
-        for name in names:
-            # get basic structure file
-            try:
-                structure = get_structure(name, distro)
-            except urllib2.HTTPError:
-                logging.error("Can not get structure for '%s'." % name)
-                continue
-
-            # get dicts of pkgname -> support timeframe string
-            get_packages_support_time(
-                structure, name, pkg_support_time, support_timeframe)
-
-    # now go over the bits in main that we have not seen (because
-    # they are not in any seed and got added manually into "main"
-    for arch in ubuntu_maintenance.PRIMARY_ARCHES:
-        rootdir = "./aptroot.%s" % distro
-        apt_pkg.config.set("APT::Architecture", arch)
-        cache = apt.Cache(rootdir=rootdir)
-        try:
-            cache.update()
-        except SystemError:
-            logging.exception("cache.update() failed")
-        cache.open()
-        for pkg in cache:
-            # ignore multiarch package names
-            if ":" in pkg.name:
-                continue
-            if not pkg.name in pkg_support_time:
-                pkg_support_time[pkg.name] = support_timeframe[-1][0]
-                logging.warn(
-                    "add package in main but not in seeds %s with %s" % (
-                        pkg.name, pkg_support_time[pkg.name]))
-
-    # now check the hints file that is used to overwrite
-    # the default seeds
-    try:
-        for line in urllib2.urlopen(hints_file):
-            line = line.strip()
-            if not line or line.startswith("#"):
-                continue
-            try:
-                (raw_pkgname, support_time) = line.split()
-                for pkgname in expand_src_pkgname(raw_pkgname):
-                    if support_time == 'unsupported':
-                        try:
-                            del pkg_support_time[pkgname]
-                            sys.stderr.write("hints-file: marking %s "
-                                             "unsupported\n" % pkgname)
-                        except KeyError:
-                            pass
-                    else:
-                        if pkg_support_time.get(pkgname) != support_time:
-                            sys.stderr.write(
-                                "hints-file: changing %s from %s to %s\n" % (
-                                    pkgname, pkg_support_time.get(pkgname),
-                                    support_time))
-                            pkg_support_time[pkgname] = support_time
-            except:
-                logging.exception("can not parse line '%s'" % line)
-    except urllib2.HTTPError as e:
-        if e.code != 404:
-            raise
-        sys.stderr.write("hints-file: %s gave 404 error\n" % hints_file)
-
-    # output suitable for the extra-override file
-    for pkgname in sorted(pkg_support_time.keys()):
-        # special case, the hints file may contain overrides that
-        # are arch-specific (like zsh-doc/armel)
-        if "/" in pkgname:
-            print "%s %s %s" % (
-                pkgname, SUPPORT_TAG, pkg_support_time[pkgname])
-        else:
-            # go over the supported arches, they are divided in
-            # first-class (PRIMARY) and second-class with different
-            # support levels
-            for arch in ubuntu_maintenance.SUPPORTED_ARCHES:
-                # ensure we do not overwrite arch-specific overwrites
-                pkgname_and_arch = "%s/%s" % (pkgname, arch)
-                if pkgname_and_arch in pkg_support_time:
-                    break
-                if arch in ubuntu_maintenance.PRIMARY_ARCHES:
-                    # arch with full LTS support
-                    print "%s %s %s" % (
-                        pkgname_and_arch, SUPPORT_TAG,
-                        pkg_support_time[pkgname])
-                else:
-                    # not a LTS supported architecture, gets only regular
-                    # support_timeframe
-                    print "%s %s %s" % (
-                        pkgname_and_arch, SUPPORT_TAG,
-                        ubuntu_maintenance.SUPPORT_TIMEFRAME[-1][0])

=== modified file 'lib/lp/archivepublisher/config.py'
--- lib/lp/archivepublisher/config.py	2012-09-20 12:00:22 +0000
+++ lib/lp/archivepublisher/config.py	2014-06-09 09:51:14 +0000
@@ -74,12 +74,10 @@
         pubconf.overrideroot = pubconf.archiveroot + '-overrides'
         pubconf.cacheroot = pubconf.archiveroot + '-cache'
         pubconf.miscroot = pubconf.archiveroot + '-misc'
-        pubconf.germinateroot = pubconf.archiveroot + '-germinate'
     else:
         pubconf.overrideroot = None
         pubconf.cacheroot = None
         pubconf.miscroot = None
-        pubconf.germinateroot = None
 
     if archive.is_main:
         pubconf.uefiroot = pubconf.archiveroot + '-uefi'
@@ -117,7 +115,6 @@
             self.cacheroot,
             self.overrideroot,
             self.miscroot,
-            self.germinateroot,
             self.temproot,
             ]
 

=== removed file 'lib/lp/archivepublisher/scripts/generate_extra_overrides.py'
--- lib/lp/archivepublisher/scripts/generate_extra_overrides.py	2012-11-10 02:21:31 +0000
+++ lib/lp/archivepublisher/scripts/generate_extra_overrides.py	1970-01-01 00:00:00 +0000
@@ -1,384 +0,0 @@
-# Copyright 2011-2012 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Generate extra overrides using Germinate."""
-
-__metaclass__ = type
-__all__ = [
-    'GenerateExtraOverrides',
-    ]
-
-from functools import partial
-import glob
-import logging
-from optparse import OptionValueError
-import os
-import re
-
-from germinate.archive import TagFile
-from germinate.germinator import Germinator
-from germinate.log import GerminateFormatter
-from germinate.seeds import (
-    SeedError,
-    SeedStructure,
-    )
-from zope.component import getUtility
-
-from lp.archivepublisher.config import getPubConfig
-from lp.registry.interfaces.distribution import IDistributionSet
-from lp.registry.interfaces.series import SeriesStatus
-from lp.services.database.policy import (
-    DatabaseBlockedPolicy,
-    SlaveOnlyDatabasePolicy,
-    )
-from lp.services.scripts.base import (
-    LaunchpadScript,
-    LaunchpadScriptFailure,
-    )
-from lp.services.utils import file_exists
-
-
-class AtomicFile:
-    """Facilitate atomic writing of files."""
-
-    def __init__(self, filename):
-        self.filename = filename
-        self.fd = open("%s.new" % self.filename, "w")
-
-    def __enter__(self):
-        return self.fd
-
-    def __exit__(self, exc_type, exc_value, exc_tb):
-        self.fd.close()
-        if exc_type is None:
-            os.rename("%s.new" % self.filename, self.filename)
-
-
-def find_operable_series(distribution):
-    """Find all the series we can operate on in this distribution.
-
-    We are allowed to modify DEVELOPMENT or FROZEN series, but should leave
-    series with any other status alone.
-    """
-    return [
-        series for series in distribution.series
-        if series.status in (SeriesStatus.DEVELOPMENT, SeriesStatus.FROZEN)]
-
-
-class GenerateExtraOverrides(LaunchpadScript):
-    """Main class for scripts/ftpmaster-tools/generate-task-overrides.py."""
-
-    def __init__(self, *args, **kwargs):
-        super(GenerateExtraOverrides, self).__init__(*args, **kwargs)
-        self.germinate_logger = None
-
-    def add_my_options(self):
-        """Add a 'distribution' context option."""
-        self.parser.add_option(
-            "-d", "--distribution", dest="distribution",
-            help="Context distribution name.")
-
-    @property
-    def name(self):
-        """See `LaunchpadScript`."""
-        # Include distribution name.  Clearer to admins, but also
-        # puts runs for different distributions under separate
-        # locks so that they can run simultaneously.
-        return "%s-%s" % (self._name, self.options.distribution)
-
-    def processOptions(self):
-        """Handle command-line options."""
-        if self.options.distribution is None:
-            raise OptionValueError("Specify a distribution.")
-
-        self.distribution = getUtility(IDistributionSet).getByName(
-            self.options.distribution)
-        if self.distribution is None:
-            raise OptionValueError(
-                "Distribution '%s' not found." % self.options.distribution)
-
-        self.series = find_operable_series(self.distribution)
-        if not self.series:
-            raise LaunchpadScriptFailure(
-                "There is no DEVELOPMENT or FROZEN distroseries for %s." %
-                self.options.distribution)
-
-    def getConfig(self):
-        """Set up a configuration object for this archive."""
-        archive = self.distribution.main_archive
-        if archive:
-            return getPubConfig(archive)
-        else:
-            raise LaunchpadScriptFailure(
-                "There is no PRIMARY archive for %s." %
-                self.options.distribution)
-
-    def setUpDirs(self):
-        """Create output directories if they did not already exist."""
-        germinateroot = self.config.germinateroot
-        if not file_exists(germinateroot):
-            self.logger.debug("Creating germinate root %s.", germinateroot)
-            os.makedirs(germinateroot)
-        miscroot = self.config.miscroot
-        if not file_exists(miscroot):
-            self.logger.debug("Creating misc root %s.", miscroot)
-            os.makedirs(miscroot)
-
-    def addLogHandler(self):
-        """Send germinate's log output to a separate file."""
-        if self.germinate_logger is not None:
-            return
-
-        self.germinate_logger = logging.getLogger("germinate")
-        self.germinate_logger.setLevel(logging.INFO)
-        self.log_file = os.path.join(
-            self.config.germinateroot, "germinate.output")
-        handler = logging.FileHandler(self.log_file, mode="w")
-        handler.setFormatter(GerminateFormatter())
-        self.germinate_logger.addHandler(handler)
-        self.germinate_logger.propagate = False
-
-    def setUp(self):
-        """Process options, and set up internal state."""
-        self.processOptions()
-        self.config = self.getConfig()
-        self.setUpDirs()
-        self.addLogHandler()
-
-    def getComponents(self, series):
-        """Get the list of components to process for a given distroseries.
-
-        Even if DistroSeries.component_names starts including partner,
-        we don't want it; this applies to the primary archive only.
-        """
-        return [component
-                for component in series.component_names
-                if component != "partner"]
-
-    def makeSeedStructures(self, series_name, flavours, seed_bases=None):
-        structures = {}
-        for flavour in flavours:
-            try:
-                structure = SeedStructure(
-                    "%s.%s" % (flavour, series_name), seed_bases=seed_bases)
-                if len(structure):
-                    structures[flavour] = structure
-                else:
-                    self.logger.warning(
-                        "Skipping empty seed structure for %s.%s",
-                        flavour, series_name)
-            except SeedError as e:
-                self.logger.warning(
-                    "Failed to fetch seeds for %s.%s: %s",
-                    flavour, series_name, e)
-        return structures
-
-    def logGerminateProgress(self, *args):
-        """Log a "progress" entry to the germinate log file.
-
-        Germinate logs quite a bit of detailed information.  To make it
-        easier to see the structure of its operation, GerminateFormatter
-        allows tagging some log entries as "progress" entries, which are
-        printed without a prefix.
-        """
-        self.germinate_logger.info(*args, extra={"progress": True})
-
-    def composeOutputPath(self, flavour, series_name, arch, base):
-        return os.path.join(
-            self.config.germinateroot,
-            "%s_%s_%s_%s" % (base, flavour, series_name, arch))
-
-    def recordOutput(self, path, seed_outputs):
-        if seed_outputs is not None:
-            seed_outputs.add(os.path.basename(path))
-
-    def writeGerminateOutput(self, germinator, structure, flavour,
-                             series_name, arch, seed_outputs=None):
-        """Write dependency-expanded output files.
-
-        These files are a reduced subset of those written by the germinate
-        command-line program.
-        """
-        path = partial(self.composeOutputPath, flavour, series_name, arch)
-
-        # The structure file makes it possible to figure out how the other
-        # output files relate to each other.
-        structure.write(path("structure"))
-        self.recordOutput(path("structure"), seed_outputs)
-
-        # "all" and "all.sources" list the full set of binary and source
-        # packages respectively for a given flavour/suite/architecture
-        # combination.
-        germinator.write_all_list(structure, path("all"))
-        self.recordOutput(path("all"), seed_outputs)
-        germinator.write_all_source_list(structure, path("all.sources"))
-        self.recordOutput(path("all.sources"), seed_outputs)
-
-        # Write the dependency-expanded output for each seed.  Several of
-        # these are used by archive administration tools, and others are
-        # useful for debugging, so it's best to just write them all.
-        for seedname in structure.names:
-            germinator.write_full_list(structure, path(seedname), seedname)
-            self.recordOutput(path(seedname), seed_outputs)
-
-    def parseTaskHeaders(self, seedtext):
-        """Parse a seed for Task headers.
-
-        seedtext is a file-like object.  Return a dictionary of Task headers,
-        with keys canonicalised to lower-case.
-        """
-        task_headers = {}
-        task_header_regex = re.compile(
-            r"task-(.*?):(.*)", flags=re.IGNORECASE)
-        for line in seedtext:
-            match = task_header_regex.match(line)
-            if match is not None:
-                key, value = match.groups()
-                task_headers[key.lower()] = value.strip()
-        return task_headers
-
-    def getTaskName(self, task_headers, flavour, seedname, primary_flavour):
-        """Work out the name of the Task to be generated from this seed.
-
-        If there is a Task-Name header, it wins; otherwise, seeds with a
-        Task-Per-Derivative header are honoured for all flavours and put in
-        an appropriate namespace, while other seeds are only honoured for
-        the first flavour and have archive-global names.
-        """
-        if "name" in task_headers:
-            return task_headers["name"]
-        elif "per-derivative" in task_headers:
-            return "%s-%s" % (flavour, seedname)
-        elif primary_flavour:
-            return seedname
-        else:
-            return None
-
-    def getTaskSeeds(self, task_headers, seedname):
-        """Return the list of seeds used to generate a task from this seed.
-
-        The list of packages in this task comes from this seed plus any
-        other seeds listed in a Task-Seeds header.
-        """
-        scan_seeds = set([seedname])
-        if "seeds" in task_headers:
-            scan_seeds.update(task_headers["seeds"].split())
-        return sorted(scan_seeds)
-
-    def writeOverrides(self, override_file, germinator, structure, arch,
-                       seedname, key, value):
-        packages = germinator.get_full(structure, seedname)
-        for package in sorted(packages):
-            print >>override_file, "%s/%s  %s  %s" % (
-                package, arch, key, value)
-
-    def germinateArchFlavour(self, override_file, germinator, series_name,
-                             arch, flavour, structure, primary_flavour,
-                             seed_outputs=None):
-        """Germinate seeds on a single flavour for a single architecture."""
-        # Expand dependencies.
-        germinator.plant_seeds(structure)
-        germinator.grow(structure)
-        germinator.add_extras(structure)
-
-        self.writeGerminateOutput(
-            germinator, structure, flavour, series_name, arch,
-            seed_outputs=seed_outputs)
-
-        write_overrides = partial(
-            self.writeOverrides, override_file, germinator, structure, arch)
-
-        # Generate apt-ftparchive "extra overrides" for Task fields.
-        seednames = [name for name in structure.names if name != "extra"]
-        for seedname in seednames:
-            with structure[seedname] as seedtext:
-                task_headers = self.parseTaskHeaders(seedtext)
-            if task_headers:
-                task = self.getTaskName(
-                    task_headers, flavour, seedname, primary_flavour)
-                if task is not None:
-                    scan_seeds = self.getTaskSeeds(task_headers, seedname)
-                    for scan_seed in scan_seeds:
-                        write_overrides(scan_seed, "Task", task)
-
-        # Generate apt-ftparchive "extra overrides" for Build-Essential
-        # fields.
-        if "build-essential" in structure.names and primary_flavour:
-            write_overrides("build-essential", "Build-Essential", "yes")
-
-    def germinateArch(self, override_file, series_name, components, arch,
-                      flavours, structures, seed_outputs=None):
-        """Germinate seeds on all flavours for a single architecture."""
-        germinator = Germinator(arch)
-
-        # Read archive metadata.
-        archive = TagFile(
-            series_name, components, arch,
-            "file://%s" % self.config.archiveroot, cleanup=True)
-        germinator.parse_archive(archive)
-
-        for flavour in flavours:
-            self.logger.info(
-                "Germinating for %s/%s/%s", flavour, series_name, arch)
-            # Add this to the germinate log as well so that that can be
-            # debugged more easily.  Log a separator line first.
-            self.logGerminateProgress("")
-            self.logGerminateProgress(
-                "Germinating for %s/%s/%s", flavour, series_name, arch)
-
-            self.germinateArchFlavour(
-                override_file, germinator, series_name, arch, flavour,
-                structures[flavour], flavour == flavours[0],
-                seed_outputs=seed_outputs)
-
-    def removeStaleOutputs(self, series_name, seed_outputs):
-        """Remove stale outputs for a series.
-
-        Any per-seed outputs not in seed_outputs are considered stale.
-        """
-        all_outputs = glob.glob(
-            os.path.join(self.config.germinateroot, "*_*_%s_*" % series_name))
-        for output in all_outputs:
-            if os.path.basename(output) not in seed_outputs:
-                os.remove(output)
-
-    def generateExtraOverrides(self, series_name, components, architectures,
-                               flavours, seed_bases=None):
-        structures = self.makeSeedStructures(
-            series_name, flavours, seed_bases=seed_bases)
-
-        if structures:
-            seed_outputs = set()
-            override_path = os.path.join(
-                self.config.miscroot,
-                "more-extra.override.%s.main" % series_name)
-            with AtomicFile(override_path) as override_file:
-                for arch in architectures:
-                    self.germinateArch(
-                        override_file, series_name, components, arch,
-                        flavours, structures, seed_outputs=seed_outputs)
-            self.removeStaleOutputs(series_name, seed_outputs)
-
-    def process(self, seed_bases=None):
-        """Do the bulk of the work."""
-        self.setUp()
-
-        for series in self.series:
-            series_name = series.name
-            components = self.getComponents(series)
-            architectures = sorted(
-                arch.architecturetag for arch in series.enabled_architectures)
-
-            # This takes a while.  Ensure that we do it without keeping a
-            # database transaction open.
-            self.txn.commit()
-            with DatabaseBlockedPolicy():
-                self.generateExtraOverrides(
-                    series_name, components, architectures, self.args,
-                    seed_bases=seed_bases)
-
-    def main(self):
-        """See `LaunchpadScript`."""
-        # This code has no need to alter the database.
-        with SlaveOnlyDatabasePolicy():
-            self.process()

=== modified file 'lib/lp/archivepublisher/tests/test_config.py'
--- lib/lp/archivepublisher/tests/test_config.py	2013-05-01 18:39:38 +0000
+++ lib/lp/archivepublisher/tests/test_config.py	2014-06-09 09:51:14 +0000
@@ -45,8 +45,6 @@
         self.assertEqual(archiveroot + "-cache", primary_config.cacheroot)
         self.assertEqual(archiveroot + "-misc", primary_config.miscroot)
         self.assertEqual(
-            archiveroot + "-germinate", primary_config.germinateroot)
-        self.assertEqual(
             self.root + "/ubuntutest-temp", primary_config.temproot)
         self.assertEqual(archiveroot + "-uefi", primary_config.uefiroot)
 
@@ -67,7 +65,6 @@
         self.assertIsNone(partner_config.overrideroot)
         self.assertIsNone(partner_config.cacheroot)
         self.assertIsNone(partner_config.miscroot)
-        self.assertIsNone(partner_config.germinateroot)
         self.assertEqual(
             self.root + "/ubuntutest-temp", partner_config.temproot)
         self.assertEqual(archiveroot + "-uefi", partner_config.uefiroot)
@@ -89,8 +86,6 @@
             archiveroot + "-overrides", copy_config.overrideroot)
         self.assertEqual(archiveroot + "-cache", copy_config.cacheroot)
         self.assertEqual(archiveroot + "-misc", copy_config.miscroot)
-        self.assertEqual(
-            archiveroot + "-germinate", copy_config.germinateroot)
         self.assertEqual(archiveroot + "-temp", copy_config.temproot)
         self.assertIsNone(copy_config.uefiroot)
 
@@ -125,7 +120,6 @@
         self.assertIsNone(self.ppa_config.overrideroot)
         self.assertIsNone(self.ppa_config.cacheroot)
         self.assertIsNone(self.ppa_config.miscroot)
-        self.assertIsNone(self.ppa_config.germinateroot)
         self.assertEqual(
             "/var/tmp/archive/ubuntutest-temp", self.ppa_config.temproot)
         uefiroot = "/var/tmp/ppa-signing-keys.test/uefi/%s/%s" % (
@@ -156,7 +150,6 @@
         self.assertIsNone(p3a_config.overrideroot)
         self.assertIsNone(p3a_config.cacheroot)
         self.assertIsNone(p3a_config.miscroot)
-        self.assertIsNone(p3a_config.germinateroot)
         self.assertEqual(
             "/var/tmp/archive/ubuntutest-temp", p3a_config.temproot)
         # It's OK for the signing keys to be in the same location as for

=== removed file 'lib/lp/archivepublisher/tests/test_generate_extra_overrides.py'
--- lib/lp/archivepublisher/tests/test_generate_extra_overrides.py	2013-09-24 05:45:06 +0000
+++ lib/lp/archivepublisher/tests/test_generate_extra_overrides.py	1970-01-01 00:00:00 +0000
@@ -1,678 +0,0 @@
-# Copyright 2011-2012 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Test for the `generate-extra-overrides` script."""
-
-__metaclass__ = type
-
-from functools import partial
-import logging
-from optparse import OptionValueError
-import os
-import tempfile
-
-from germinate import (
-    archive,
-    germinator,
-    seeds,
-    )
-import transaction
-
-from lp.archivepublisher.publishing import (
-    get_packages_path,
-    get_sources_path,
-    )
-from lp.archivepublisher.scripts.generate_extra_overrides import (
-    AtomicFile,
-    GenerateExtraOverrides,
-    )
-from lp.archivepublisher.utils import RepositoryIndexFile
-from lp.registry.interfaces.pocket import PackagePublishingPocket
-from lp.registry.interfaces.series import SeriesStatus
-from lp.services.log.logger import DevNullLogger
-from lp.services.osutils import (
-    ensure_directory_exists,
-    open_for_writing,
-    write_file,
-    )
-from lp.services.scripts.base import LaunchpadScriptFailure
-from lp.services.scripts.tests import run_script
-from lp.services.utils import file_exists
-from lp.soyuz.enums import PackagePublishingStatus
-from lp.testing import TestCaseWithFactory
-from lp.testing.fakemethod import FakeMethod
-from lp.testing.faketransaction import FakeTransaction
-from lp.testing.layers import (
-    LaunchpadZopelessLayer,
-    ZopelessDatabaseLayer,
-    )
-
-
-def file_contents(path):
-    """Return the contents of the file at path."""
-    with open(path) as handle:
-        return handle.read()
-
-
-class TestAtomicFile(TestCaseWithFactory):
-    """Tests for the AtomicFile helper class."""
-
-    layer = ZopelessDatabaseLayer
-
-    def test_atomic_file_creates_file(self):
-        # AtomicFile creates the named file with the requested contents.
-        self.useTempDir()
-        filename = self.factory.getUniqueString()
-        text = self.factory.getUniqueString()
-        with AtomicFile(filename) as test:
-            test.write(text)
-        self.assertEqual(text, file_contents(filename))
-
-    def test_atomic_file_removes_dot_new(self):
-        # AtomicFile does not leave .new files lying around.
-        self.useTempDir()
-        filename = self.factory.getUniqueString()
-        with AtomicFile(filename):
-            pass
-        self.assertFalse(file_exists("%s.new" % filename))
-
-
-class TestGenerateExtraOverrides(TestCaseWithFactory):
-    """Tests for the actual `GenerateExtraOverrides` script."""
-
-    layer = LaunchpadZopelessLayer
-
-    def setUp(self):
-        super(TestGenerateExtraOverrides, self).setUp()
-        self.seeddir = self.makeTemporaryDirectory()
-        # XXX cjwatson 2011-12-06 bug=694140: Make sure germinate doesn't
-        # lose its loggers between tests, due to Launchpad's messing with
-        # global log state.
-        archive._logger = logging.getLogger("germinate.archive")
-        germinator._logger = logging.getLogger("germinate.germinator")
-        seeds._logger = logging.getLogger("germinate.seeds")
-
-    def assertFilesEqual(self, expected_path, observed_path):
-        self.assertEqual(
-            file_contents(expected_path), file_contents(observed_path))
-
-    def makeDistro(self):
-        """Create a distribution for testing.
-
-        The distribution will have a root directory set up, which will
-        be cleaned up after the test.  It will have an attached archive.
-        """
-        return self.factory.makeDistribution(
-            publish_root_dir=unicode(self.makeTemporaryDirectory()))
-
-    def makeScript(self, distribution, run_setup=True, extra_args=None):
-        """Create a script for testing."""
-        test_args = []
-        if distribution is not None:
-            test_args.extend(["-d", distribution.name])
-        if extra_args is not None:
-            test_args.extend(extra_args)
-        script = GenerateExtraOverrides(test_args=test_args)
-        script.logger = DevNullLogger()
-        script.txn = FakeTransaction()
-        if distribution is not None and run_setup:
-            script.setUp()
-        else:
-            script.distribution = distribution
-        return script
-
-    def setUpDistroAndScript(self, series_statuses=["DEVELOPMENT"], **kwargs):
-        """Helper wrapping distro and script setup."""
-        self.distro = self.makeDistro()
-        self.distroseries = [
-            self.factory.makeDistroSeries(
-                distribution=self.distro, status=SeriesStatus.items[status])
-            for status in series_statuses]
-        self.script = self.makeScript(self.distro, **kwargs)
-
-    def setUpComponent(self, component=None):
-        """Create a component and attach it to all distroseries."""
-        if component is None:
-            component = self.factory.makeComponent()
-        for distroseries in self.distroseries:
-            self.factory.makeComponentSelection(
-                distroseries=distroseries, component=component)
-        return component
-
-    def makePackage(self, component, dases, **kwargs):
-        """Create a published source and binary package for testing."""
-        package = self.factory.makeDistributionSourcePackage(
-            distribution=dases[0].distroseries.distribution)
-        spph = self.factory.makeSourcePackagePublishingHistory(
-            distroseries=dases[0].distroseries,
-            pocket=PackagePublishingPocket.RELEASE,
-            status=PackagePublishingStatus.PUBLISHED,
-            sourcepackagename=package.name, component=component)
-        for das in dases:
-            build = self.factory.makeBinaryPackageBuild(
-                source_package_release=spph.sourcepackagerelease,
-                distroarchseries=das, processor=das.processor)
-            bpr = self.factory.makeBinaryPackageRelease(
-                binarypackagename=package.name, build=build,
-                component=component, architecturespecific=True,
-                **kwargs)
-            lfa = self.factory.makeLibraryFileAlias(
-                filename="%s.deb" % package.name)
-            transaction.commit()
-            bpr.addFile(lfa)
-            self.factory.makeBinaryPackagePublishingHistory(
-                binarypackagerelease=bpr, distroarchseries=das,
-                pocket=PackagePublishingPocket.RELEASE,
-                status=PackagePublishingStatus.PUBLISHED)
-        return package
-
-    def makeIndexFiles(self, script, distroseries):
-        """Create a limited subset of index files for testing."""
-        ensure_directory_exists(script.config.temproot)
-
-        for component in distroseries.components:
-            source_index = RepositoryIndexFile(
-                get_sources_path(script.config, distroseries.name, component),
-                script.config.temproot)
-            for spp in distroseries.getSourcePackagePublishing(
-                    PackagePublishingPocket.RELEASE, component,
-                    distroseries.main_archive):
-                stanza = spp.getIndexStanza().encode("utf-8") + "\n\n"
-                source_index.write(stanza)
-            source_index.close()
-
-            for arch in distroseries.architectures:
-                package_index = RepositoryIndexFile(
-                    get_packages_path(
-                        script.config, distroseries.name, component, arch),
-                    script.config.temproot)
-                for bpp in distroseries.getBinaryPackagePublishing(
-                        arch.architecturetag, PackagePublishingPocket.RELEASE,
-                        component, distroseries.main_archive):
-                    stanza = bpp.getIndexStanza().encode("utf-8") + "\n\n"
-                    package_index.write(stanza)
-                package_index.close()
-
-    def composeSeedPath(self, flavour, series_name, seed_name):
-        return os.path.join(
-            self.seeddir, "%s.%s" % (flavour, series_name), seed_name)
-
-    def makeSeedStructure(self, flavour, series_name, seed_names,
-                          seed_inherit={}):
-        """Create a simple seed structure file."""
-        structure_path = self.composeSeedPath(
-            flavour, series_name, "STRUCTURE")
-        with open_for_writing(structure_path, "w") as structure:
-            for seed_name in seed_names:
-                inherit = seed_inherit.get(seed_name, [])
-                line = "%s: %s" % (seed_name, " ".join(inherit))
-                print >>structure, line.strip()
-
-    def makeSeed(self, flavour, series_name, seed_name, entries,
-                 headers=None):
-        """Create a simple seed file."""
-        seed_path = self.composeSeedPath(flavour, series_name, seed_name)
-        with open_for_writing(seed_path, "w") as seed:
-            if headers is not None:
-                for header in headers:
-                    print >>seed, header
-                print >>seed
-            for entry in entries:
-                print >>seed, " * %s" % entry
-
-    def getTaskNameFromSeed(self, script, flavour, series_name, seed,
-                            primary_flavour):
-        """Use script to parse a seed and return its task name."""
-        seed_path = self.composeSeedPath(flavour, series_name, seed)
-        with open(seed_path) as seed_text:
-            task_headers = script.parseTaskHeaders(seed_text)
-        return script.getTaskName(
-            task_headers, flavour, seed, primary_flavour)
-
-    def getTaskSeedsFromSeed(self, script, flavour, series_name, seed):
-        """Use script to parse a seed and return its task seed list."""
-        seed_path = self.composeSeedPath(flavour, series_name, seed)
-        with open(seed_path) as seed_text:
-            task_headers = script.parseTaskHeaders(seed_text)
-        return script.getTaskSeeds(task_headers, seed)
-
-    def test_name_is_consistent(self):
-        # Script instances for the same distro get the same name.
-        distro = self.factory.makeDistribution()
-        self.assertEqual(
-            GenerateExtraOverrides(test_args=["-d", distro.name]).name,
-            GenerateExtraOverrides(test_args=["-d", distro.name]).name)
-
-    def test_name_is_unique_for_each_distro(self):
-        # Script instances for different distros get different names.
-        self.assertNotEqual(
-            GenerateExtraOverrides(
-                test_args=["-d", self.factory.makeDistribution().name]).name,
-            GenerateExtraOverrides(
-                test_args=["-d", self.factory.makeDistribution().name]).name)
-
-    def test_requires_distro(self):
-        # The --distribution or -d argument is mandatory.
-        script = self.makeScript(None)
-        self.assertRaises(OptionValueError, script.processOptions)
-
-    def test_requires_real_distro(self):
-        # An incorrect distribution name is flagged as an invalid option
-        # value.
-        script = self.makeScript(
-            None, extra_args=["-d", self.factory.getUniqueString()])
-        self.assertRaises(OptionValueError, script.processOptions)
-
-    def test_looks_up_distro(self):
-        # The script looks up and keeps the distribution named on the
-        # command line.
-        self.setUpDistroAndScript()
-        self.assertEqual(self.distro, self.script.distribution)
-
-    def test_prefers_development_distro_series(self):
-        # The script prefers a DEVELOPMENT series for the named
-        # distribution over CURRENT and SUPPORTED series.
-        self.setUpDistroAndScript(["SUPPORTED", "CURRENT", "DEVELOPMENT"])
-        self.assertEqual([self.distroseries[2]], self.script.series)
-
-    def test_permits_frozen_distro_series(self):
-        # If there is no DEVELOPMENT series, a FROZEN one will do.
-        self.setUpDistroAndScript(["SUPPORTED", "CURRENT", "FROZEN"])
-        self.assertEqual([self.distroseries[2]], self.script.series)
-
-    def test_requires_development_frozen_distro_series(self):
-        # If there is no DEVELOPMENT or FROZEN series, the script fails.
-        self.setUpDistroAndScript(["SUPPORTED", "CURRENT"], run_setup=False)
-        self.assertRaises(LaunchpadScriptFailure, self.script.processOptions)
-
-    def test_multiple_development_frozen_distro_series(self):
-        # If there are multiple DEVELOPMENT or FROZEN series, they are all
-        # used.
-        self.setUpDistroAndScript(
-            ["DEVELOPMENT", "DEVELOPMENT", "FROZEN", "FROZEN"])
-        self.assertContentEqual(self.distroseries, self.script.series)
-
-    def test_components_exclude_partner(self):
-        # If a 'partner' component exists, it is excluded.
-        self.setUpDistroAndScript()
-        self.setUpComponent(component="main")
-        self.setUpComponent(component="partner")
-        self.assertEqual(1, len(self.script.series))
-        self.assertEqual(
-            ["main"], self.script.getComponents(self.script.series[0]))
-
-    def test_compose_output_path_in_germinateroot(self):
-        # Output files are written to the correct locations under
-        # germinateroot.
-        self.setUpDistroAndScript()
-        flavour = self.factory.getUniqueString()
-        arch = self.factory.getUniqueString()
-        base = self.factory.getUniqueString()
-        output = self.script.composeOutputPath(
-            flavour, self.distroseries[0].name, arch, base)
-        self.assertEqual(
-            "%s/%s_%s_%s_%s" % (
-                self.script.config.germinateroot, base, flavour,
-                self.distroseries[0].name, arch),
-            output)
-
-    def test_make_seed_structures_missing_seeds(self):
-        # makeSeedStructures ignores missing seeds.
-        self.setUpDistroAndScript()
-        series_name = self.distroseries[0].name
-        flavour = self.factory.getUniqueString()
-
-        structures = self.script.makeSeedStructures(
-            series_name, [flavour], seed_bases=["file://%s" % self.seeddir])
-        self.assertEqual({}, structures)
-
-    def test_make_seed_structures_empty_seed_structure(self):
-        # makeSeedStructures ignores an empty seed structure.
-        self.setUpDistroAndScript()
-        series_name = self.distroseries[0].name
-        flavour = self.factory.getUniqueString()
-        self.makeSeedStructure(flavour, series_name, [])
-
-        structures = self.script.makeSeedStructures(
-            series_name, [flavour], seed_bases=["file://%s" % self.seeddir])
-        self.assertEqual({}, structures)
-
-    def test_make_seed_structures_valid_seeds(self):
-        # makeSeedStructures reads valid seeds successfully.
-        self.setUpDistroAndScript()
-        series_name = self.distroseries[0].name
-        flavour = self.factory.getUniqueString()
-        seed = self.factory.getUniqueString()
-        self.makeSeedStructure(flavour, series_name, [seed])
-        self.makeSeed(flavour, series_name, seed, [])
-
-        structures = self.script.makeSeedStructures(
-            series_name, [flavour], seed_bases=["file://%s" % self.seeddir])
-        self.assertIn(flavour, structures)
-
-    def fetchGerminatedOverrides(self, script, distroseries, arch, flavours):
-        """Helper to call script.germinateArch and return overrides."""
-        structures = script.makeSeedStructures(
-            distroseries.name, flavours,
-            seed_bases=["file://%s" % self.seeddir])
-
-        override_fd, override_path = tempfile.mkstemp()
-        with os.fdopen(override_fd, "w") as override_file:
-            script.germinateArch(
-                override_file, distroseries.name,
-                script.getComponents(distroseries), arch, flavours,
-                structures)
-        return file_contents(override_path).splitlines()
-
-    def test_germinate_output(self):
-        # A single call to germinateArch produces output for all flavours on
-        # one architecture.
-        self.setUpDistroAndScript()
-        series_name = self.distroseries[0].name
-        component = self.setUpComponent()
-        das = self.factory.makeDistroArchSeries(
-            distroseries=self.distroseries[0])
-        arch = das.architecturetag
-        one = self.makePackage(component, [das])
-        two = self.makePackage(component, [das])
-        self.makeIndexFiles(self.script, self.distroseries[0])
-
-        flavour_one = self.factory.getUniqueString()
-        flavour_two = self.factory.getUniqueString()
-        seed = self.factory.getUniqueString()
-        self.makeSeedStructure(flavour_one, series_name, [seed])
-        self.makeSeed(flavour_one, series_name, seed, [one.name])
-        self.makeSeedStructure(flavour_two, series_name, [seed])
-        self.makeSeed(flavour_two, series_name, seed, [two.name])
-
-        overrides = self.fetchGerminatedOverrides(
-            self.script, self.distroseries[0], arch,
-            [flavour_one, flavour_two])
-        self.assertEqual([], overrides)
-
-        seed_dir_one = os.path.join(
-            self.seeddir, "%s.%s" % (flavour_one, series_name))
-        self.assertFilesEqual(
-            os.path.join(seed_dir_one, "STRUCTURE"),
-            self.script.composeOutputPath(
-                flavour_one, series_name, arch, "structure"))
-        self.assertTrue(file_exists(self.script.composeOutputPath(
-            flavour_one, series_name, arch, "all")))
-        self.assertTrue(file_exists(self.script.composeOutputPath(
-            flavour_one, series_name, arch, "all.sources")))
-        self.assertTrue(file_exists(self.script.composeOutputPath(
-            flavour_one, series_name, arch, seed)))
-
-        seed_dir_two = os.path.join(
-            self.seeddir, "%s.%s" % (flavour_two, series_name))
-        self.assertFilesEqual(
-            os.path.join(seed_dir_two, "STRUCTURE"),
-            self.script.composeOutputPath(
-                flavour_two, series_name, arch, "structure"))
-        self.assertTrue(file_exists(self.script.composeOutputPath(
-            flavour_two, series_name, arch, "all")))
-        self.assertTrue(file_exists(self.script.composeOutputPath(
-            flavour_two, series_name, arch, "all.sources")))
-        self.assertTrue(file_exists(self.script.composeOutputPath(
-            flavour_two, series_name, arch, seed)))
-
-    def test_germinate_output_task(self):
-        # germinateArch produces Task extra overrides.
-        self.setUpDistroAndScript()
-        series_name = self.distroseries[0].name
-        component = self.setUpComponent()
-        das = self.factory.makeDistroArchSeries(
-            distroseries=self.distroseries[0])
-        arch = das.architecturetag
-        one = self.makePackage(component, [das])
-        two = self.makePackage(component, [das], depends=one.name)
-        three = self.makePackage(component, [das])
-        self.makePackage(component, [das])
-        self.makeIndexFiles(self.script, self.distroseries[0])
-
-        flavour = self.factory.getUniqueString()
-        seed_one = self.factory.getUniqueString()
-        seed_two = self.factory.getUniqueString()
-        self.makeSeedStructure(flavour, series_name, [seed_one, seed_two])
-        self.makeSeed(
-            flavour, series_name, seed_one, [two.name],
-            headers=["Task-Description: one"])
-        self.makeSeed(
-            flavour, series_name, seed_two, [three.name],
-            headers=["Task-Description: two"])
-
-        overrides = self.fetchGerminatedOverrides(
-            self.script, self.distroseries[0], arch, [flavour])
-        expected_overrides = [
-            "%s/%s  Task  %s" % (one.name, arch, seed_one),
-            "%s/%s  Task  %s" % (two.name, arch, seed_one),
-            "%s/%s  Task  %s" % (three.name, arch, seed_two),
-            ]
-        self.assertContentEqual(expected_overrides, overrides)
-
-    def test_task_name(self):
-        # The Task-Name field is honoured.
-        series_name = self.factory.getUniqueString()
-        package = self.factory.getUniqueString()
-        script = self.makeScript(None)
-
-        flavour = self.factory.getUniqueString()
-        seed = self.factory.getUniqueString()
-        task = self.factory.getUniqueString()
-        self.makeSeed(
-            flavour, series_name, seed, [package],
-            headers=["Task-Name: %s" % task])
-
-        observed_task = self.getTaskNameFromSeed(
-            script, flavour, series_name, seed, True)
-        self.assertEqual(task, observed_task)
-
-    def test_task_per_derivative(self):
-        # The Task-Per-Derivative field is honoured.
-        series_name = self.factory.getUniqueString()
-        package = self.factory.getUniqueString()
-        script = self.makeScript(None)
-
-        flavour_one = self.factory.getUniqueString()
-        flavour_two = self.factory.getUniqueString()
-        seed_one = self.factory.getUniqueString()
-        seed_two = self.factory.getUniqueString()
-        self.makeSeed(
-            flavour_one, series_name, seed_one, [package],
-            headers=["Task-Description: one"])
-        self.makeSeed(
-            flavour_one, series_name, seed_two, [package],
-            headers=["Task-Per-Derivative: 1"])
-        self.makeSeed(
-            flavour_two, series_name, seed_one, [package],
-            headers=["Task-Description: one"])
-        self.makeSeed(
-            flavour_two, series_name, seed_two, [package],
-            headers=["Task-Per-Derivative: 1"])
-
-        observed_task_one_one = self.getTaskNameFromSeed(
-            script, flavour_one, series_name, seed_one, True)
-        observed_task_one_two = self.getTaskNameFromSeed(
-            script, flavour_one, series_name, seed_two, True)
-        observed_task_two_one = self.getTaskNameFromSeed(
-            script, flavour_two, series_name, seed_one, False)
-        observed_task_two_two = self.getTaskNameFromSeed(
-            script, flavour_two, series_name, seed_two, False)
-
-        # seed_one is not per-derivative, so it is honoured only for
-        # flavour_one and has a global name.
-        self.assertEqual(seed_one, observed_task_one_one)
-        self.assertIsNone(observed_task_two_one)
-
-        # seed_two is per-derivative, so it is honoured for both flavours
-        # and has the flavour name prefixed.
-        self.assertEqual(
-            "%s-%s" % (flavour_one, seed_two), observed_task_one_two)
-        self.assertEqual(
-            "%s-%s" % (flavour_two, seed_two), observed_task_two_two)
-
-    def test_task_seeds(self):
-        # The Task-Seeds field is honoured.
-        series_name = self.factory.getUniqueString()
-        one = self.getUniqueString()
-        two = self.getUniqueString()
-        script = self.makeScript(None)
-
-        flavour = self.factory.getUniqueString()
-        seed_one = self.factory.getUniqueString()
-        seed_two = self.factory.getUniqueString()
-        self.makeSeed(flavour, series_name, seed_one, [one])
-        self.makeSeed(
-            flavour, series_name, seed_two, [two],
-            headers=["Task-Seeds: %s" % seed_one])
-
-        task_seeds = self.getTaskSeedsFromSeed(
-            script, flavour, series_name, seed_two)
-        self.assertContentEqual([seed_one, seed_two], task_seeds)
-
-    def test_germinate_output_build_essential(self):
-        # germinateArch produces Build-Essential extra overrides.
-        self.setUpDistroAndScript()
-        series_name = self.distroseries[0].name
-        component = self.setUpComponent()
-        das = self.factory.makeDistroArchSeries(
-            distroseries=self.distroseries[0])
-        arch = das.architecturetag
-        package = self.makePackage(component, [das])
-        self.makeIndexFiles(self.script, self.distroseries[0])
-
-        flavour = self.factory.getUniqueString()
-        seed = "build-essential"
-        self.makeSeedStructure(flavour, series_name, [seed])
-        self.makeSeed(flavour, series_name, seed, [package.name])
-
-        overrides = self.fetchGerminatedOverrides(
-            self.script, self.distroseries[0], arch, [flavour])
-        self.assertContentEqual(
-            ["%s/%s  Build-Essential  yes" % (package.name, arch)], overrides)
-
-    def test_removes_only_stale_files(self):
-        # removeStaleOutputs removes only stale germinate output files.
-        self.setUpDistroAndScript()
-        series_name = self.distroseries[0].name
-        seed_old_file = "old_flavour_%s_i386" % series_name
-        seed_new_file = "new_flavour_%s_i386" % series_name
-        other_file = "other-file"
-        output = partial(os.path.join, self.script.config.germinateroot)
-        for base in (seed_old_file, seed_new_file, other_file):
-            write_file(output(base), "")
-        self.script.removeStaleOutputs(series_name, set([seed_new_file]))
-        self.assertFalse(os.path.exists(output(seed_old_file)))
-        self.assertTrue(os.path.exists(output(seed_new_file)))
-        self.assertTrue(os.path.exists(output(other_file)))
-
-    def test_process_missing_seeds(self):
-        # The script ignores series with no seed structures.
-        flavour = self.factory.getUniqueString()
-        self.setUpDistroAndScript(
-            ["DEVELOPMENT", "DEVELOPMENT"], extra_args=[flavour])
-        self.setUpComponent()
-        self.factory.makeDistroArchSeries(distroseries=self.distroseries[0])
-        self.factory.makeDistroArchSeries(distroseries=self.distroseries[1])
-        self.makeIndexFiles(self.script, self.distroseries[1])
-        seed = self.factory.getUniqueString()
-        self.makeSeedStructure(flavour, self.distroseries[1].name, [seed])
-        self.makeSeed(flavour, self.distroseries[1].name, seed, [])
-
-        self.script.process(seed_bases=["file://%s" % self.seeddir])
-        self.assertFalse(os.path.exists(os.path.join(
-            self.script.config.miscroot,
-            "more-extra.override.%s.main" % self.distroseries[0].name)))
-        self.assertTrue(os.path.exists(os.path.join(
-            self.script.config.miscroot,
-            "more-extra.override.%s.main" % self.distroseries[1].name)))
-
-    def test_process_removes_only_stale_files(self):
-        # The script removes only stale germinate output files.
-        flavour = self.factory.getUniqueString()
-        self.setUpDistroAndScript(extra_args=[flavour])
-        series_name = self.distroseries[0].name
-        self.setUpComponent()
-        das = self.factory.makeDistroArchSeries(
-            distroseries=self.distroseries[0])
-        arch = das.architecturetag
-        self.makeIndexFiles(self.script, self.distroseries[0])
-
-        seed_old = self.factory.getUniqueString()
-        seed_new = self.factory.getUniqueString()
-        self.makeSeedStructure(flavour, series_name, [seed_old])
-        self.makeSeed(flavour, series_name, seed_old, [])
-        self.script.process(seed_bases=["file://%s" % self.seeddir])
-        output = partial(
-            self.script.composeOutputPath, flavour, series_name, arch)
-        self.assertTrue(os.path.exists(output(seed_old)))
-        self.makeSeedStructure(flavour, series_name, [seed_new])
-        self.makeSeed(flavour, series_name, seed_new, [])
-        self.script.process(seed_bases=["file://%s" % self.seeddir])
-        self.assertTrue(os.path.exists(os.path.join(self.script.log_file)))
-        self.assertTrue(os.path.exists(output("structure")))
-        self.assertTrue(os.path.exists(output("all")))
-        self.assertTrue(os.path.exists(output("all.sources")))
-        self.assertTrue(os.path.exists(output(seed_new)))
-        self.assertFalse(os.path.exists(output(seed_old)))
-
-    def test_process_skips_disabled_distroarchseries(self):
-        # The script does not generate overrides for disabled DistroArchSeries.
-        flavour = self.factory.getUniqueString()
-        self.setUpDistroAndScript(extra_args=[flavour])
-        das = self.factory.makeDistroArchSeries(
-            distroseries=self.distroseries[0])
-        self.factory.makeDistroArchSeries(
-            distroseries=self.distroseries[0], enabled=False)
-        self.script.generateExtraOverrides = FakeMethod()
-        self.script.process()
-        self.assertEqual(1, self.script.generateExtraOverrides.call_count)
-        self.assertEqual(
-            [das.architecturetag],
-            self.script.generateExtraOverrides.calls[0][0][2])
-
-    def test_main(self):
-        # If run end-to-end, the script generates override files containing
-        # output for all architectures, and sends germinate's log output to
-        # a file.
-        flavour = self.factory.getUniqueString()
-        self.setUpDistroAndScript(extra_args=[flavour])
-        series_name = self.distroseries[0].name
-        component = self.setUpComponent()
-        das_one = self.factory.makeDistroArchSeries(
-            distroseries=self.distroseries[0])
-        das_two = self.factory.makeDistroArchSeries(
-            distroseries=self.distroseries[0])
-        package = self.makePackage(component, [das_one, das_two])
-        self.makeIndexFiles(self.script, self.distroseries[0])
-
-        seed = self.factory.getUniqueString()
-        self.makeSeedStructure(flavour, series_name, [seed])
-        self.makeSeed(
-            flavour, series_name, seed, [package.name],
-            headers=["Task-Description: task"])
-
-        self.script.process(seed_bases=["file://%s" % self.seeddir])
-        override_path = os.path.join(
-            self.script.config.miscroot,
-            "more-extra.override.%s.main" % series_name)
-        expected_overrides = [
-            "%s/%s  Task  %s" % (package.name, das_one.architecturetag, seed),
-            "%s/%s  Task  %s" % (package.name, das_two.architecturetag, seed),
-            ]
-        self.assertContentEqual(
-            expected_overrides, file_contents(override_path).splitlines())
-
-        log_file = os.path.join(
-            self.script.config.germinateroot, "germinate.output")
-        self.assertIn("Downloading file://", file_contents(log_file))
-
-    def test_run_script(self):
-        # The script will run stand-alone.
-        distro = self.makeDistro()
-        self.factory.makeDistroSeries(distro)
-        transaction.commit()
-        retval, out, err = run_script(
-            "cronscripts/generate-extra-overrides.py",
-            ["-d", distro.name, "-q"])
-        self.assertEqual(0, retval)

=== removed directory 'lib/lp/soyuz/scripts/tests/germinate-test-data'
=== removed directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin'
=== removed file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile'
--- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile	2010-11-11 18:22:00 +0000
+++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-bin/lockfile	1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-# This is a mock "lockfile" command that is used during the test
-# There is no need to have the real lockfile installed (its part
-# of procmail) because there can be no multiple germinate instances
-# while we run the tests
-
-exit 1

=== removed directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root'
=== removed directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts'
=== removed file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/generate-extra-overrides.py'
--- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/generate-extra-overrides.py	2011-12-14 15:21:50 +0000
+++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/generate-extra-overrides.py	1970-01-01 00:00:00 +0000
@@ -1,5 +0,0 @@
-#! /usr/bin/python
-#
-# We don't need to run generate-extra-overrides.py when testing
-# maintenance-check.py.  We could, but it would slow down the tests and its
-# output is not interesting here.

=== removed directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/publishing'
=== removed symlink 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/cronscripts/publishing/maintenance-check.py'
=== target was u'../../../../../../../../../cronscripts/publishing/maintenance-check.py'
=== removed directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts'
=== removed directory 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools'
=== removed file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py'
--- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py	2012-04-16 13:56:45 +0000
+++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py	1970-01-01 00:00:00 +0000
@@ -1,27 +0,0 @@
-#!/usr/bin/python
-#
-# This is a mock version of the lp-query-distro.py script that
-# returns static data so that the cron.germinate shell script
-# can be tested.
-
-import sys
-
-
-def error_and_exit():
-    sys.stderr.write("ERROR: I'm a mock, I only support 'supported' as "
-                     "argument\n")
-    sys.exit(1)
-
-
-def main(args):
-    # There is only a very limited subset of arguments that we support,
-    # test for it and error if it looks wrong
-    if len(args) == 2:
-        distro = args[1]
-        if distro == "supported":
-            return "hardy jaunty karmic lucid maverick"
-    error_and_exit()
-
-
-if __name__ == "__main__":
-    print main(sys.argv)

=== removed file 'lib/lp/soyuz/scripts/tests/test_cron_germinate.py'
--- lib/lp/soyuz/scripts/tests/test_cron_germinate.py	2011-12-14 15:21:50 +0000
+++ lib/lp/soyuz/scripts/tests/test_cron_germinate.py	1970-01-01 00:00:00 +0000
@@ -1,226 +0,0 @@
-#!/usr/bin/python
-# Copyright 2010 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""This is a test for the soyuz cron.germinate script."""
-
-__metaclass__ = type
-
-import copy
-import gzip
-import os
-import subprocess
-
-from lp.testing import TestCase
-
-
-class TestCronGerminate(TestCase):
-
-    DISTRO_NAMES = ["platform", "ubuntu", "kubuntu", "netbook"]
-    DISTS = ["hardy", "lucid", "maverick"]
-    DEVELOPMENT_DIST = "natty"
-    COMPONENTS = ["main", "restricted", "universe", "multiverse"]
-    ARCHES = ["i386", "amd64", "armel", "powerpc"]
-    BASEPATH = os.path.abspath(os.path.dirname(__file__))
-    source_root = os.path.normpath(
-        os.path.join(BASEPATH, "..", "..", "..", "..", ".."))
-
-    def setUp(self):
-        super(TestCronGerminate, self).setUp()
-
-        # Setup a temp archive directory and populate it with the right
-        # sub-directories.
-        self.tmpdir = self.makeTemporaryDirectory()
-        self.archive_dir = self.setup_mock_archive_environment()
-        self.ubuntu_misc_dir = os.path.join(self.archive_dir, "ubuntu-misc")
-        self.ubuntu_germinate_dir = os.path.join(
-            self.archive_dir, "ubuntu-germinate")
-        # Create a mock archive environment for all the distros we support and
-        # also include "updates" and "security".
-        for dist in self.DISTS + [self.DEVELOPMENT_DIST]:
-            self.populate_mock_archive_environment(
-                self.archive_dir, self.COMPONENTS, self.ARCHES, dist)
-            for component in ["security", "updates"]:
-                self.populate_mock_archive_environment(
-                    self.archive_dir, self.COMPONENTS, self.ARCHES,
-                    "%s-%s" % (dist, component))
-        # Generate test dummies for maintenance-time.py, if this is set to
-        # "None" instead it will use the network to test against the real
-        # data.
-        self.germinate_output_dir = self.setup_mock_germinate_output()
-
-    def create_directory_if_missing(self, directory):
-        """Create the given directory if it does not exist."""
-        if not os.path.exists(directory):
-            os.makedirs(directory)
-
-    def create_directory_list_if_missing(self, directory_list):
-        """Create the given directories from the list if they don't exist."""
-        for directory in directory_list:
-            self.create_directory_if_missing(directory)
-
-    def create_gzip_file(self, filepath, content=""):
-        """Create a gziped file in the given path with the given content.
-
-        If no content is given a empty file is created.
-        """
-        gz = gzip.GzipFile(filepath, "w")
-        gz.write(content)
-        gz.close()
-
-    def create_file(self, filepath, content=""):
-        """Create a file in the given path with the given content.
-
-        If no content is given a empty file is created.
-        """
-        f = open(filepath, "w")
-        f.write(content)
-        f.close()
-
-    def setup_mock_germinate_output(self):
-        # empty structure files
-        germinate_output_dir = os.path.join(
-            self.tmpdir, "germinate-test-data", "germinate-output")
-        dirs = []
-        for distro_name in self.DISTRO_NAMES:
-            for distro_series in self.DISTS:
-                dirs.append(
-                    os.path.join(
-                        germinate_output_dir,
-                        "%s.%s" % (distro_name, distro_series)))
-        self.create_directory_list_if_missing(dirs)
-        for dir in dirs:
-            self.create_file(os.path.join(dir, "structure"))
-        return germinate_output_dir
-
-    def setup_mock_archive_environment(self):
-        """
-        Creates a mock archive environment and populate it with the
-        subdirectories that germinate will expect.
-        """
-        archive_dir = os.path.join(
-            self.tmpdir, "germinate-test-data", "ubuntu-archive")
-        ubuntu_misc_dir = os.path.join(archive_dir, "ubuntu-misc")
-        ubuntu_germinate_dir = os.path.join(archive_dir, "ubuntu-germinate")
-        ubuntu_dists_dir = os.path.join(archive_dir, "ubuntu", "dists")
-        self.create_directory_list_if_missing([
-                archive_dir,
-                ubuntu_misc_dir,
-                ubuntu_germinate_dir,
-                ubuntu_dists_dir])
-        return archive_dir
-
-    def populate_mock_archive_environment(self, archive_dir, components_list,
-                                          arches_list, current_devel_distro):
-        """
-        Populates a mock archive environment with empty source packages and
-        empty binary packages.
-        """
-        for component in components_list:
-            # Create the environment for the source packages.
-            targetdir = os.path.join(
-                archive_dir,
-                "ubuntu/dists/%s/%s/source" % (
-                    current_devel_distro, component))
-            self.create_directory_if_missing(targetdir)
-            self.create_gzip_file(os.path.join(targetdir, "Sources.gz"))
-
-            # Create the environment for the binary packages.
-            for arch in arches_list:
-                for subpath in ["", "debian-installer"]:
-                    targetdir = os.path.join(
-                        self.archive_dir,
-                        "ubuntu/dists/%s/%s/%s/binary-%s" % (
-                            current_devel_distro, component, subpath, arch))
-                    self.create_directory_if_missing(targetdir)
-                    self.create_gzip_file(os.path.join(
-                            targetdir, "Packages.gz"))
-
-    def create_fake_environment(self, basepath, archive_dir,
-                                germinate_output_dir):
-        """
-        Create a fake process envirionment based on os.environ that sets
-        TEST_ARCHIVEROOT, TEST_LAUNCHPADROOT and modifies PATH to point to the
-        mock lp-bin directory.
-        """
-        fake_environ = copy.copy(os.environ)
-        fake_environ["TEST_ARCHIVEROOT"] = os.path.abspath(
-            os.path.join(archive_dir, "ubuntu"))
-        fake_environ["TEST_LAUNCHPADROOT"] = os.path.abspath(
-            os.path.join(basepath, "germinate-test-data/mock-lp-root"))
-        # Set the PATH in the fake environment so that our mock lockfile is
-        # used.
-        fake_environ["PATH"] = "%s:%s" % (
-            os.path.abspath(os.path.join(
-                basepath, "germinate-test-data/mock-bin")),
-            os.environ["PATH"])
-        # test dummies for get-support-timeframe.py, they need to be
-        # in URI format
-        if germinate_output_dir:
-            # redirect base url to the mock environment
-            fake_environ["MAINTENANCE_CHECK_BASE_URL"] = "file://%s" % \
-                germinate_output_dir
-            # point to mock archive root
-            archive_root_url = "file://%s" % os.path.abspath(
-                os.path.join(archive_dir, "ubuntu"))
-            fake_environ["MAINTENANCE_CHECK_ARCHIVE_ROOT"] = archive_root_url
-            # maintenance-check.py expects a format string
-            hints_file_url = (
-                germinate_output_dir + "/platform.%s/SUPPORTED_HINTS")
-            for distro in self.DISTS:
-                open(hints_file_url % distro, "w")
-            fake_environ["MAINTENANCE_CHECK_HINTS_DIR_URL"] = "file://%s" % \
-                os.path.abspath(hints_file_url)
-            # add hints override to test that feature
-            f=open(hints_file_url % "lucid", "a")
-            f.write("linux-image-2.6.32-25-server 5y\n")
-            f.close()
-        return fake_environ
-
-    def test_maintenance_update(self):
-        """
-        Test the maintenance-check.py porition of the soyuz cron.germinate
-        shell script by running it inside a fake environment and ensure that
-        it did update the "Support" override information for apt-ftparchive
-        without destroying/modifying the information that the "germinate"
-        script added to it earlier.
-        """
-        # Write into more-extras.overrides to ensure it is alive after we
-        # mucked around.
-        canary = "abrowser Task mock\n"
-        # Build fake environment based on the real one.
-        fake_environ = self.create_fake_environment(
-            self.BASEPATH, self.archive_dir, self.germinate_output_dir)
-        # Create mock override data files that include the canary string
-        # so that we can test later if it is still there.
-        for dist in self.DISTS:
-            self.create_file(
-                os.path.join(self.ubuntu_misc_dir,
-                             "more-extra.override.%s.main" % dist),
-                canary)
-
-        # Run cron.germinate in the fake environment.
-        cron_germinate_path = os.path.join(
-            self.source_root, "cronscripts", "publishing", "cron.germinate")
-        subprocess.call(
-            [cron_germinate_path], env=fake_environ, cwd=self.BASEPATH)
-
-        # And check the output it generated for correctness.
-        for dist in self.DISTS:
-            supported_override_file = os.path.join(
-                self.ubuntu_misc_dir,
-                "more-extra.override.%s.main.supported" % dist)
-            self.assertTrue(os.path.exists(supported_override_file),
-                            "no override file created for '%s'" % dist)
-            main_override_file = os.path.join(
-                self.ubuntu_misc_dir,
-                "more-extra.override.%s.main" % dist)
-            self.assertIn(canary, open(main_override_file).read())
-
-        # Check here if we got the data from maintenance-check.py that
-        # we expected. This is a kernel name from lucid-updates and it
-        # will be valid for 5 years.
-        needle = "linux-image-2.6.32-25-server/i386 Supported 5y"
-        lucid_supported_override_file = os.path.join(
-            self.ubuntu_misc_dir, "more-extra.override.lucid.main")
-        self.assertIn(needle, open(lucid_supported_override_file).read())


Follow ups