Commits

Michael Tharp committed 483e0da

Relocate to rpath_proddef.

  • Participants
  • Parent commits eeadc5d

Comments (0)

Files changed (22)

 export datadir = $(prefix)/share
 export mandir = $(datadir)/man
 export sitedir = $(libdir)/python$(PYVERSION)/site-packages/
-export pydir = $(sitedir)/rpath_common/
+export pydir = $(sitedir)/rpath_proddef/
 export initdir = /etc/init.d
 export sysconfdir = /etc/sysconfig
 export docdir = $(datadir)/doc/rpath-product-definition-$(VERSION)
 #
-# Copyright (c) 2006-2008 rPath, Inc.
+# Copyright (c) 2006-2009 rPath, Inc.
 #
 # This program is distributed under the terms of the Common Public License,
 # version 1.0. A copy of this license should have been distributed with this
 # the name of packages containing a product definition
 export DISTDIR = $(TOPDIR)/rpath-product-definition-$(VERSION)
 
-SUBDIRS=rpath_common xsd doc
+SUBDIRS=rpath_proddef xsd doc
 
 dist_files = $(extra_files)
 
 releases, including 0.x releases and any automated builds.
 
 To use the latest version of the interface:
-    from rpath_common import proddef
+    import rpath_proddef
 To use a specific API Version of the interface:
-    from rpath_common.proddef import api1 as proddef
+    from rpath_proddef import api1 as proddef
 
 The schema definitions are versioned with major and minor numbers.
 Within a major version, only new elements will be added; elements

File doc/example.py

 Example code for interacting with rPath product definition xml files.
 """
 
-from rpath_common.proddef import api1 as proddef
+from rpath_proddef import api1 as proddef
 import sys
 
 # This is an example of how this module would be used to generate the XML

File pylint/init_pylint.py

 sys.path.insert(0, os.environ['CONARY_PATH'])
 sys.path.insert(0, os.path.abspath('../..'))
 
-from rpath_common.proddef import api1
+from rpath_proddef import api1

File pylint/run_pylint

 cp init_pylint.py reports
 cd reports
 
-pylint --init-hook='import sys, os; sys.path.append("."); import init_pylint' --rcfile='../pylintrc' ../../rpath_common/proddef/api1.py;
+pylint --init-hook='import sys, os; sys.path.append("."); import init_pylint' --rcfile='../pylintrc' ../../rpath_proddef/api1.py;
 rm init_pylint*;
 for file in $(ls); do
    if [ ! -s $file ]; then

File rpath_common/Makefile

-#
-# Copyright (c) 2006-2008 rPath, Inc.
-#
-# This program is distributed under the terms of the Common Public License,
-# version 1.0. A copy of this license should have been distributed with this
-# source file in a file called LICENSE. If it is not present, the license
-# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
-#
-# This program is distributed in the hope that it will be useful, but
-# without any warranty; without even the implied warranty of merchantability
-# or fitness for a particular purpose. See the Common Public License for
-# full details.
-#
-
-# Note: do not list __init__.py in python_files -- it is here only
-# to support testing out of the tree.  When distributed, this
-# file is provided by the rpath-common package instead.
-
-SUBDIRS = proddef
-SYMLINKS = xmllib
-
-dist_files = Makefile __init__.py
-
-all: default-all default-subdirs symlinks
-
-install: all default-install install-subdirs
-
-dist: default-dist
-
-clean: default-clean symlink-clean
-
-symlink-clean:
-	@rm -f $(SYMLINKS)
-
-symlinks:
-	[ -z "$$XMLLIB_PATH" ] || [ -h xmllib ] || ln -s $$XMLLIB_PATH/rpath_common/xmllib .
-
-
-include ../Make.rules
-include ../Make.defs

File rpath_common/__init__.py

Empty file removed.

File rpath_common/proddef/Makefile

-#
-# Copyright (c) 2008 rPath, Inc.
-#
-# This program is distributed under the terms of the Common Public License,
-# version 1.0. A copy of this license should have been distributed with this
-# source file in a file called LICENSE. If it is not present, the license
-# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
-#
-# This program is distributed in the hope that it will be useful, but
-# without any warranty; without even the implied warranty of merchantability
-# or fitness for a particular purpose. See the Common Public License for
-# full details.
-#
-
-python_files =	$(wildcard *.py)
-
-dist_files = Makefile proddef_constants.py.in $(python_files)
-
-all: default-all proddef_constants.py
-
-proddef_constants.py: proddef_constants.py.in ../../Makefile ../../Make.defs Makefile
-	sed -e s,@version@,$(VERSION),g \
-	$< > $@
-
-install: all pyfiles-install default-install
-	install proddef_constants.py $(DESTDIR)$(pydir)/proddef/proddef_constants.py
-	$(PYTHON) -c "import compileall; compileall.compile_dir('$(DESTDIR)$(pydir)/proddef', ddir='$(pydir)/proddef', quiet=1)"
-	$(PYTHON) -OO -c "import compileall; compileall.compile_dir('$(DESTDIR)$(pydir)/proddef', ddir='$(pydir)/proddef', quiet=1)"
-
-dist: default-dist
-
-clean: default-clean
-	rm -f proddef_constants.py
-
-include ../../Make.rules
-include ../../Make.defs

File rpath_common/proddef/__init__.py

-#
-# Copyright (c) 2008 rPath, Inc.
-#
-# This program is distributed under the terms of the Common Public License,
-# version 1.0. A copy of this license should have been distributed with this
-# source file in a file called LICENSE. If it is not present, the license
-# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
-#
-# This program is distributed in the hope that it will be useful, but
-# without any warranty; without even the implied warranty of merchantability
-# or fitness for a particular purpose. See the Common Public License for
-# full details.
-#
-"""
-The rPath Common Library Module for Product Definition
-
-This module provides a stable interface for reading and writing
-rPath product definition XML files.  This interface will be
-backward-compatible within major versions of this package.
-The C{VERSION} data element is a string containing the version.
-The portion of the string before the initial C{.} character is the
-major version.
-
-All interfaces in this modules that do not start with a C{_}
-character are public interfaces.
-
-If the C{VERSION} starts with C{0.}, none of the included
-interfaces is stable and may change without warning.
-
-To use the latest version of the interface::
-    from rpath_common import proddef
-To use a specific API Version of the interface::
-    from rpath_common.proddef import api1 as proddef
-"""
-
-# Default to current API version
-#pylint: disable-msg=W0401
-from rpath_common.proddef.api1 import *
-
-# Import the automatically-generated VERSION
-#pylint: disable-msg=W0212
-from rpath_common.proddef.proddef_constants import _VERSION as VERSION

File rpath_common/proddef/_xmlConstants.py

-#
-# Copyright (c) 2006-2008 rPath, Inc.
-#
-# This program is distributed under the terms of the Common Public License,
-# version 1.0. A copy of this license should have been distributed with this
-# source file in a file called LICENSE. If it is not present, the license
-# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
-#
-# This program is distributed in the hope that it will be useful, but
-# without any warranty; without even the implied warranty of merchantability
-# or fitness for a particular purpose. See the Common Public License for
-# full details.
-#
-"""
-@var defaultNamespaceList: List of supported namespaces, the preferred
-    namespace being first. Normally, augmenting the schema in a
-    backwards-compatible way (i.e. with pure additions) should not result in a
-    new namespace being generated.
-@type defaultNamespaceList: list
-@var xmlSchemaNamespace: XML Schema namespace
-@type xmlSchemaNamespace: C{str}
-@var xmlSchemaLocation: XML Schema location
-@type xmlSchemaLocaltion: C{str}
-"""
-
-defaultNamespaceList = [ "http://www.rpath.com/permanent/rpd-2.0.xsd" ]
-xmlSchemaNamespace = "http://www.w3.org/2001/XMLSchema-instance"
-xmlSchemaLocation = "http://www.rpath.com/permanent/rpd-2.0.xsd rpd-2.0.xsd"

File rpath_common/proddef/api1.py

-#
-# Copyright (c) 2008 rPath, Inc.
-#
-# This program is distributed under the terms of the Common Public License,
-# version 1.0. A copy of this license should have been distributed with this
-# source file in a file called LICENSE. If it is not present, the license
-# is always available at http://www.rpath.com/permanent/licenses/CPL-1.0.
-#
-# This program is distributed in the hope that it will be useful, but
-# without any warranty; without even the implied warranty of merchantability
-# or fitness for a particular purpose. See the Common Public License for
-# full details.
-#
-"""
-The rPath Common Library Module for Product Definition, API version 1
-
-All interfaces in this modules that do not start with a C{_}
-character are public interfaces.
-"""
-
-__all__ = [ 'MissingInformationError',
-            'ProductDefinition',
-            'ProductDefinitionError',
-            'StageNotFoundError',
-            'ProductDefinitionTroveNotFoundError',
-            'ProductDefinitionFileNotFoundError',
-            'RepositoryError',
-            'PlatformLabelMissingError',
-            'ArchitectureNotFoundError',
-            'FlavorSetNotFoundError',
-            'ContainerTemplateNotFoundError',
-            'BuildTemplateNotFoundError',
-            'InvalidSchemaVersionError',
-            ]
-
-import itertools
-import os
-import StringIO
-import weakref
-
-from conary import changelog
-from conary import errors as conaryErrors
-from conary import versions as conaryVersions
-from conary.conaryclient import filetypes, cmdline
-from conary.deps import deps as conaryDeps
-from conary.repository import errors as repositoryErrors
-
-from rpath_common.xmllib import api1 as xmllib
-from rpath_common.proddef import _xmlConstants
-from rpath_common.proddef import imageTypes
-
-#{ Exception classes
-class ProductDefinitionError(Exception):
-    "Base class for product definition exceptions"
-
-class MissingInformationError(ProductDefinitionError):
-    """
-    Raised when attempting to synthesize a label when there isn't enough
-    information to generate it.
-    """
-
-class StageNotFoundError(ProductDefinitionError):
-    "Raised when no such stage exists."
-
-class ArchitectureNotFoundError(ProductDefinitionError):
-    "Raised when no such architecture exists."
-
-class FlavorSetNotFoundError(ProductDefinitionError):
-    "Raised when no such flavor set exists."
-
-class ContainerTemplateNotFoundError(ProductDefinitionError):
-    "Raised when no such container template exists."
-
-class BuildTemplateNotFoundError(ProductDefinitionError):
-    "Raised when no such build template exists."
-
-class ProductDefinitionTroveNotFoundError(ProductDefinitionError):
-    """
-    Raised when the trove containing the product definition file could not
-    be found in the repository
-    """
-
-class ProductDefinitionFileNotFoundError(ProductDefinitionError):
-    "Raised when the product definition file was not found in the repository"
-
-class RepositoryError(ProductDefinitionError):
-    "Generic error raised when a repository error was caught"
-
-class PlatformLabelMissingError(ProductDefinitionError):
-    "Raised when the platform label is missing, and a rebase was requested"
-
-class InvalidSchemaVersionError(ProductDefinitionError):
-    "Raised when the schema version in a product definition file is not recognized."
-
-#}
-
-class BaseDefinition(object):
-    version = '3.0'
-    defaultNamespace = _xmlConstants.defaultNamespaceList[0]
-    xmlSchemaLocation = _xmlConstants.xmlSchemaLocation
-
-    schemaDir = "/usr/share/rpath_common"
-
-    def __init__(self, fromStream = None, validate = False, schemaDir = None):
-        """
-        Initialize a ProductDefinition object, getting data from the optional
-        XML stream.
-        @param fromStream: An optional XML string or file
-        @type fromStream: C{str} or C{file}
-        @param validate: Validate before parsing (off by default)
-        @type validate: C{bool}
-        @param schemaDir: A directory where schema files are stored
-        @type schemaDir: C{str}
-        """
-
-        self._initFields()
-
-        if fromStream:
-            if isinstance(fromStream, (str, unicode)):
-                fromStream = StringIO.StringIO(fromStream)
-            self.parseStream(fromStream, validate = validate,
-                             schemaDir = schemaDir)
-
-    def getBaseFlavor(self):
-        """
-        @return: the base flavor
-        @rtype: C{str}
-        """
-        return self.baseFlavor
-
-    def setBaseFlavor(self, baseFlavor):
-        """
-        Set the base flavor.
-        @param baseFlavor: the base flavor
-        @type baseFlavor: C{str}
-        """
-        self.baseFlavor = baseFlavor
-
-    def getSearchPaths(self):
-        """
-        @return: the search paths from this product definition
-        @rtype: C{list} of C{_SearchPath} objects
-        """
-        return self.searchPaths
-
-    def getResolveTroves(self):
-        """
-        @return: the search paths from this product definition, filtering
-                 any results that have the isResolveTrove attribute set to 
-                 False. This is a subset of the results from getSearchPaths
-        @rtype: C{list} of C{_SearchPath} objects
-        """
-        return [x for x in self.searchPaths 
-                if x.isResolveTrove or x.isResolveTrove is None]
-
-    def getGroupSearchPaths(self):
-        """
-        @return: the search paths from this product definition, filtering
-                 any results that do not have isGroupSearchPathTrove attribute
-                 set to False. This is a subset of the results 
-                 from getSearchPaths
-        @rtype: C{list} of C{_SearchPath} objects
-        """
-        return  [x for x in self.searchPaths 
-                 if x.isGroupSearchPathTrove 
-                    or x.isGroupSearchPathTrove is None]
-
-    def clearSearchPaths(self):
-        """
-        Delete all searchPaths.
-        @return: None
-        @rtype None
-        """
-        self.searchPaths = _SearchPaths()
-
-    def getFactorySources(self):
-        """
-        @return: the factory sources from this product definition
-        @rtype: C{list} of C{_FactorySource} objects
-        """
-        return self.factorySources
-
-    def clearFactorySources(self):
-        """
-        Delete all factorySources.
-        @return: None
-        @rtype None
-        """
-        self.factorySources = _FactorySources()
-
-    def addSearchPath(self, troveName = None, label = None, version = None,
-                      isResolveTrove = True, isGroupSearchPathTrove = True):
-        """
-        Add an search path.
-        @param troveName: the trove name for the search path.
-        @type troveName: C{str} or C{None}
-        @param label: Label for the search path
-        @type label: C{str} or C{None}
-        @param version: Version for the search path
-        @param version: C{str} or C{None}
-        @param isResolveTrove: set to False if this element should be not
-               be returned for getResolveTroves()  (defaults to True)
-        @param isGroupSearchPathTrove: set to False if this element should be 
-               not be returned for getGroupSearchPaths() (defaults to True)
-        """
-        assert(isResolveTrove or isGroupSearchPathTrove)
-        self._addSource(troveName, label, version, _SearchPath,
-                self.searchPaths, isResolveTrove = isResolveTrove,
-                isGroupSearchPathTrove = isGroupSearchPathTrove)
-
-    def addFactorySource(self, troveName = None, label = None, version = None):
-        """
-        Add a factory source.
-        @param troveName: the trove name for the factory source.
-        @type troveName: C{str} or C{None}
-        @param label: Label for the factory source
-        @type label: C{str} or C{None}
-        @param version: Version for the factory source
-        @param version: C{str} or C{None}
-        """
-        self._addSource(troveName, label, version, _FactorySource, self.factorySources)
-
-    def getArchitectures(self):
-        """
-        @return: all defined architectures for both proddef and platform
-        @rtype: C{list}
-        """
-        return self.architectures
-
-    def hasArchitecture(self, name):
-        """
-        @param name: architecture name
-        @type name: C{str}
-        @rtype: C{bool}
-        """
-        return name in [ x.name for x in self.getArchitectures() ]
-
-    def getArchitecture(self, name, default = -1):
-        """
-        @param name: architecture name
-        @type name: C{str}
-        @param default: if an architecture with this name is not found, return
-        this value. If not specified, C{ArchitectureNotFoundError} is raised.
-        @rtype: Architecture object
-        @raises C{ArchitectureNotFoundError}: if architecture is not found, and
-        no default was specified.
-        """
-        arches = self.getArchitectures()
-        for arch in arches:
-            if arch.name == name:
-                return arch
-        if default != -1:
-            return default
-        raise ArchitectureNotFoundError(name)
-
-    def addArchitecture(self, name, displayName, flavor):
-        """
-        Add an architecture.
-        @param name: name of architecture to add
-        @type name: C{str}
-        @param displayName: human readable name of the architecture
-        @type displayName: C{str}
-        @param flavor: flavor of architecture to add
-        @type flavor: C{str}
-        """
-        for obj in self.architectures[:]:
-            if obj.name == name:
-                self.architectures.remove(obj)
-        obj = _Architecture(name = name, displayName = displayName,
-                flavor = flavor)
-        self.architectures.append(obj)
-
-    def clearArchitectures(self):
-        """
-        Reset architectures.
-        """
-        self.architectures = _Architectures()
-
-    def getFlavorSets(self):
-        """
-        @return: all defined flavor sets
-        @rtype: C{list} of FlavorSet objects
-        """
-        return self.flavorSets
-
-    def getFlavorSet(self, name, default = -1):
-        """
-        @param name: flavor set name
-        @type name: C{str}
-        @param default: if an flavor set with this name is not found,
-            return this value. If not specified, C{FlavorSetNotFoundError}
-            is raised.
-        @rtype: FlavorSet object
-        @raises C{FlavorSetNotFoundError}: if flavor set is not found, and
-        no default was specified.
-        """
-        flavorSets = self.getFlavorSets()
-        for fs in flavorSets:
-            if fs.name == name:
-                return fs
-        if default != -1:
-            return default
-        raise FlavorSetNotFoundError(name)
-
-    def addFlavorSet(self, name, displayName, flavor):
-        """
-        add a flavor set.
-        @param name: name of flavor set to add
-        @type name: C{str}
-        @param displayName: human readable name of the architecture
-        @type displayName: C{str}
-        @param flavor: flavor of flavor set to add
-        @type flavor: C{str}
-        """
-        for obj in self.flavorSets[:]:
-            if obj.name == name:
-                self.flavorSets.remove(obj)
-        obj = _FlavorSet(name = name, displayName = displayName,
-                flavor = flavor)
-        self.flavorSets.append(obj)
-
-    def clearFlavorSets(self):
-        """
-        Reset flavor sets.
-        """
-        self.flavorSets = _FlavorSets()
-
-    def getContainerTemplates(self):
-        """
-        @return: all defined container templates
-        @rtype: C{list} of ContainerTemplate objects
-        """
-        return self.containerTemplates
-
-    def getContainerTemplate(self, containerFormat, default = -1):
-        """
-        @param containerFormat: container template containerFormat
-        @type containerFormat: C{str}
-        @param default: if a container template with this containerFormat is not found,
-            return this value. If not specified, C{ContainerTemplateNotFoundError}
-            is raised.
-        @rtype: ContainerTemplate object
-        @raises C{ContainerTemplateNotFoundError}: if container template is not found, and
-        no default was specified.
-        """
-        containerTemplates = self.getContainerTemplates()
-        for tmpl in containerTemplates:
-            if tmpl.containerFormat == containerFormat:
-                return tmpl
-        if default != -1:
-            return default
-        raise ContainerTemplateNotFoundError(containerFormat)
-
-    def addContainerTemplate(self, image):
-        """
-        add a container template.
-        @param image: Image
-        @type image: C{imageTypes.Image}
-        """
-        self.containerTemplates.append(image)
-
-    def clearContainerTemplates(self):
-        """
-        Reset container templates.
-        """
-        self.containerTemplates = _ContainerTemplates()
-
-    def getBuildTemplates(self):
-        """
-        @return: all defined build templates
-        @rtype: C{list} of BuildTemplate objects
-        """
-        return self.buildTemplates
-
-    def getBuildTemplate(self, name, default = -1):
-        """
-        @param name: build template name
-        @type name: C{str}
-        @param default: if a build template with this name is not found,
-            return this value. If not specified, C{BuildTemplateNotFoundError}
-            is raised.
-        @rtype: BuildTemplate object
-        @raises C{BuildTemplateNotFoundError}: if build template is not found, and
-        no default was specified.
-        """
-        buildTemplates = self.getBuildTemplates()
-        for tmpl in buildTemplates:
-            if tmpl.name == name:
-                return tmpl
-        if default != -1:
-            return default
-        raise BuildTemplateNotFoundError(name)
-
-    def addBuildTemplate(self, name, displayName, architectureRef,
-            containerTemplateRef, flavorSetRef = None):
-        """
-        add a build template.
-        @param name: name of the build template
-        @type name: C{str}
-        @param displayName: human readable name of the build template
-        @type displayName: C{str}
-        @param architectureRef: reference to architecture
-        @type architectureRef: C{str}
-        @param containerTemplateRef: reference to container template
-        @type containerTemplateRef: C{str}
-        @pararm flavorSetRef: reference to flavorSet
-        @type flavorSetRef: C{str}
-        """
-        tmpl = _BuildTemplate(name, displayName, architectureRef,
-                containerTemplateRef, flavorSetRef = flavorSetRef)
-        self.buildTemplates.append(tmpl)
-
-    def clearBuildTemplates(self):
-        """
-        Reset build templates.
-        """
-        self.buildTemplates = _BuildTemplates()
-
-    def _addSource(self, troveName, label, version, cls, intList, **kwargs):
-        "Internal function for adding a Source"
-        if label is not None:
-            if isinstance(label, conaryVersions.Label):
-                label = str(label)
-        obj = cls(troveName = troveName, label = label, version = version,
-                **kwargs)
-        intList.append(obj)
-
-    def _saveToRepository(self, conaryClient, label, message = None):
-        if message is None:
-            message = "Automatic checkin\n"
-
-        recipe = self._recipe.replace('@NAME@', self._troveName)
-        recipe = recipe.replace('@VERSION@', self.__class__.version)
-
-        stream = StringIO.StringIO()
-        self.serialize(stream)
-        pathDict = {
-            "%s.recipe" % self._troveName : filetypes.RegularFile(
-                contents = recipe, config=True),
-            self._troveFileNames[0] : filetypes.RegularFile(
-                contents = stream.getvalue(), config=True),
-        }
-        cLog = changelog.ChangeLog(name = conaryClient.cfg.name,
-                                   contact = conaryClient.cfg.contact,
-                                   message = message)
-        troveName = '%s:source' % self._troveName
-        cs = conaryClient.createSourceTrove(troveName, str(label),
-            self.__class__.version, pathDict, cLog)
-
-        repos = conaryClient.getRepos()
-        repos.commitChangeSet(cs)
-
-    def _getStreamFromRepository(self, conaryClient, label):
-        repos = conaryClient.getRepos()
-        troveName = '%s:source' % self._troveName
-        troveSpec = (troveName, label, None)
-        try:
-            troves = repos.findTroves(None, [ troveSpec ])
-        except conaryErrors.TroveNotFound:
-            raise ProductDefinitionTroveNotFoundError("%s=%s" % (troveName, label))
-        except conaryErrors.RepositoryError, e:
-            raise RepositoryError(str(e))
-        # At this point, troveSpec is in troves and its value should not be
-        # the empty list.
-        nvfs = troves[troveSpec]
-        #if not nvfs:
-        #    raise ProductDefinitionTroveNotFoundError("%s=%s" % (troveName, label))
-        nvfs = troves[troveSpec]
-        n,v,f = nvfs[0]
-        if hasattr(repos, 'getFileContentsFromTrove'):
-            contents = None
-            for troveFileName in self._troveFileNames:
-                try:
-                    contents = repos.getFileContentsFromTrove(n,v,f,
-                                                  [troveFileName])[0]
-                except repositoryErrors.PathsNotFound:
-                    pass
-            if contents is None:
-                raise ProductDefinitionFileNotFoundError()
-            return contents.get(), (n,v,f)
-
-        trvCsSpec = (n, (None, None), (v, f), True)
-        cs = conaryClient.createChangeSet([ trvCsSpec ], withFiles = True,
-                                          withFileContents = True)
-        for thawTrvCs in cs.iterNewTroveList():
-            score = None
-            fileSpec = None
-            for newFile in thawTrvCs.getNewFileList():
-                if newFile[1] in self._troveFileNames:
-                    idx = self._troveFileNames.index(newFile[1])
-                    if score is None or idx < score:
-                        score = idx
-                        fileSpec = newFile
-
-            if not paths:
-                continue
-            # Fetch file from changeset
-            pathId, _, fileId, _ = fileSpec
-            fileContents = cs.getFileContents(pathId, fileId)
-            return fileContents[1].get(), thawTrvCs.getNewNameVersionFlavor()
-
-        # Couldn't find the file we expected; die
-        raise ProductDefinitionFileNotFoundError("%s=%s" % (troveName, label))
-
-    def _initFields(self):
-        self.baseFlavor = None
-        self.searchPaths = _SearchPaths()
-        self.factorySources = _FactorySources()
-        self.architectures = _Architectures()
-        self.flavorSets = _FlavorSets()
-        self.containerTemplates = _ContainerTemplates()
-        self.buildTemplates = _BuildTemplates()
-
-    @classmethod
-    def _newNode(self, name, value):
-        node = xmllib.StringNode(name = name).characters(value)
-        return node
-
-class ProductDefinition(BaseDefinition):
-    """
-    Represents the definition of a product.
-    @cvar version:
-    @type version: C{str}
-    @cvar defaultNamespace:
-    @type defaultNamespace: C{str}
-    @cvar xmlSchemaLocation:
-    @type xmlSchemaLocation: C{str}
-    @cvar _imageTypeDispatcher: an object factory for imageType objects
-    @type _imageTypeDispatcher: C{xmllib.NodeDispatcher}
-    @cvar schemaDir: Directory where schema definitions are stored
-    @type schemaDir: C{str}
-    """
-    _imageTypeDispatcher = xmllib.NodeDispatcher({})
-
-    _troveName = 'product-definition'
-    _troveFileNames = [
-        'product-definition.xml',
-    ]
-
-    _recipe = '''
-#
-# Copyright (c) 2008 rPath, Inc.
-#
-
-class ProductDefinitionRecipe(PackageRecipe):
-    name = "@NAME@"
-    version = "@VERSION@"
-
-    def setup(r):
-        """
-        This recipe is a stub created to allow users to manually
-        check in changes to the product definition XML.
-
-        No other recipe actions need to be added beyond this point.
-        """
-'''
-
-    def __str__(self):
-        troveName = self.getTroveName()
-        try:
-            prodDefLabel = self.getProductDefinitionLabel()
-        except MissingInformationError:
-            # This is probably the best we can do. we don't want to backtrace
-            # in this case.
-            prodDefLabel = None
-        return "<Product Definition: %s=%s>" % (troveName, prodDefLabel)
-
-    def __eq__(self, obj):
-        for key, val in self.__dict__.iteritems():
-            val2 = obj.__getattribute__(key)
-            if val != val2:
-                return False
-        return True
-
-    def __ne__(self, obj):
-        return not self.__eq__(obj)
-
-    def copy(self):
-        outStr = StringIO.StringIO()
-        self.serialize(outStr)
-        inStr = StringIO.StringIO(outStr.getvalue())
-        return ProductDefinition(inStr)
-
-    def parseStream(self, stream, validate = False, schemaDir = None):
-        """
-        Initialize the current object from an XML stream.
-        @param stream: An XML stream
-        @type stream: C{file}
-        @param validate: Validate before parsing (off by default)
-        @type validate: C{bool}
-        @param schemaDir: A directory where schema files are stored
-        @type schemaDir: C{str}
-        """
-        self._initFields()
-        binder = xmllib.DataBinder()
-        binder.registerType(_ProductDefinition, 'productDefinition')
-        xmlObj = binder.parseFile(stream, validate = validate,
-                                  schemaDir = schemaDir or self.schemaDir)
-        self.productName = getattr(xmlObj, 'productName', None)
-        self.productDescription = getattr(xmlObj, 'productDescription', None)
-        self.productShortname = getattr(xmlObj, 'productShortname', None)
-        self.productVersion = getattr(xmlObj, 'productVersion', None)
-        self.productVersionDescription = getattr(xmlObj,
-            'productVersionDescription', None)
-        self.conaryRepositoryHostname = getattr(xmlObj,
-            'conaryRepositoryHostname', None)
-        self.conaryNamespace = getattr(xmlObj, 'conaryNamespace', None)
-        self.sourceGroup = getattr(xmlObj, 'sourceGroup', None)
-        self.imageGroup = getattr(xmlObj, 'imageGroup', None)
-        self.baseLabel = getattr(xmlObj, 'baseLabel', None)
-        self.baseFlavor = getattr(xmlObj, 'baseFlavor', None)
-        self.stages.extend(getattr(xmlObj, 'stages', []))
-        self.searchPaths.extend(getattr(xmlObj, 'searchPaths', []))
-        self.factorySources.extend(getattr(xmlObj, 'factorySources', []))
-        self.architectures.extend(getattr(xmlObj, 'architectures', []))
-        self.flavorSets.extend(getattr(xmlObj, 'flavorSets', []))
-        self.containerTemplates.extend(getattr(xmlObj, 'containerTemplates', []))
-        self.buildTemplates.extend(getattr(xmlObj, 'buildTemplates', []))
-        self.buildDefinition.extend(getattr(xmlObj, 'buildDefinition', []))
-        # Add (weak) reference to the product definition
-        for bd in self.buildDefinition:
-            bd.setProductDefinition(self)
-        self.platform = getattr(xmlObj, 'platform', None)
-
-        self.secondaryLabels = getattr(xmlObj, 'secondaryLabels', None)
-
-    def serialize(self, stream):
-        """
-        Serialize the current object as an XML stream.
-        @param stream: stream to write the serialized object
-        @type stream: C{file}
-        """
-        attrs = {'version' : self.version,
-                 'xmlns' : self.defaultNamespace,
-                 'xmlns:xsi' : xmllib.DataBinder.xmlSchemaNamespace,
-                 "xsi:schemaLocation" : self.xmlSchemaLocation,
-        }
-        nameSpaces = {}
-        serObj = _ProductDefinitionSerialization("productDefinition",
-            attrs, nameSpaces, self)
-        binder = xmllib.DataBinder()
-        stream.write(binder.toXml(serObj))
-
-    def saveToRepository(self, client, message = None):
-        """
-        Save a C{ProductDefinition} object to a Conary repository.
-        @param client: A Conary client object
-        @type client: C{conaryclient.ConaryClient}
-        @param message: An optional commit message
-        @type message: C{str}
-        """
-        label = self.getProductDefinitionLabel()
-        return self._saveToRepository(client, label, message = message)
-
-    def loadFromRepository(self, client):
-        """
-        Load a C{ProductDefinition} object from a Conary repository.
-        Prior to calling this method, the C{ProductDefinition} object should
-        be initialized by calling C{setProductShortname},
-        C{setProductVersion}, C{setConaryRepositoryHostname} and
-        C{setConaryNamespace}.
-        @param client: A Conary client object
-        @type client: C{conaryclient.ConaryClient}
-        @raises C{RepositoryError}:
-        @raises C{ProductDefinitionTroveNotFoundError}:
-        @raises C{ProductDefinitionFileNotFoundError}:
-        """
-        label = self.getProductDefinitionLabel()
-        stream, nvf = self._getStreamFromRepository(client, label)
-        stream.seek(0)
-        self.parseStream(stream)
-
-    def getProductName(self):
-        """
-        @return: the product name
-        @rtype: C{str}
-        """
-        return self.productName
-
-    def setProductName(self, productName):
-        """
-        Set the product name
-        @param productName: the product name
-        @type productName: C{str}
-        """
-        self.productName = productName
-
-    def getProductDescription(self):
-        """
-        @return: the product description
-        @rtype: C{str}
-        """
-        return self.productDescription
-
-    def setProductDescription(self, productDescription):
-        """
-        Set the product description
-        @param productDescription: the product description
-        @type productDescription: C{str}
-        """
-        self.productDescription = productDescription
-
-    def getProductShortname(self):
-        """
-        @return: the product shortname
-        @rtype: C{str}
-        """
-        return self.productShortname
-
-    def setProductShortname(self, productShortname):
-        """
-        @param productShortname: the product's shortname
-        @type productShortname: C{str}
-        """
-        self.productShortname = productShortname
-
-    def getProductVersion(self):
-        """
-        @return: the product version
-        @rtype: C{str}
-        """
-        return self.productVersion
-
-    def setProductVersion(self, productVersion):
-        """
-        Set the product version
-        @param productVersion: the product version
-        @type productVersion: C{str}
-        """
-        self.productVersion = productVersion
-
-    def getProductVersionDescription(self):
-        """
-        @return: the product version description
-        @rtype: C{str}
-        """
-        return self.productVersionDescription
-
-    def setProductVersionDescription(self, productVersionDescription):
-        """
-        Set the product version description
-        @param productVersionDescription: the product version description
-        @type productVersionDescription: C{str}
-        """
-        self.productVersionDescription = productVersionDescription
-
-    def getConaryRepositoryHostname(self):
-        """
-        @return: the Conary repository's hostname (e.g. conary.example.com)
-        @rtype: C{str}
-        """
-        return self.conaryRepositoryHostname
-
-    def setConaryRepositoryHostname(self, conaryRepositoryHostname):
-        """
-        Set the Conary repository hostname
-        @param conaryRepositoryHostname: the fully-qualified hostname for
-           the repository
-        @type conaryRepositoryHostname: C{str}
-        """
-        self.conaryRepositoryHostname = conaryRepositoryHostname
-
-    def getConaryNamespace(self):
-        """
-        @return: the Conary namespace to use for this product
-        @rtype: C{str}
-        """
-        return self.conaryNamespace
-
-    def setConaryNamespace(self, conaryNamespace):
-        """
-        Set the Conary namespace
-        @param conaryNamespace: the Conary namespace
-        @type conaryNamespace: C{str}
-        """
-        self.conaryNamespace = conaryNamespace
-
-    def getSourceGroup(self):
-        """
-        @return: the source group, if none is set, default to the image group
-        @rtype: C{str}
-        """
-        if self.sourceGroup:
-            return self.sourceGroup
-        else:
-            return None
-
-    def setSourceGroup(self, sourceGroup):
-        """
-        Set the source group name
-        @param sourceGroup: the image group name
-        @type sourceGroup: C{str}
-        """
-        self.sourceGroup = sourceGroup
-
-    def getImageGroup(self):
-        """
-        @return: the image group
-        @rtype: C{str}
-        """
-        return self.imageGroup
-
-    def setImageGroup(self, imageGroup):
-        """
-        Set the image group name
-        @param imageGroup: the image group name
-        @type imageGroup: C{str}
-        """
-        self.imageGroup = imageGroup
-
-    def getBaseFlavor(self):
-        """
-        @return: the base flavor
-        @rtype: C{str}
-        """
-        flv = conaryDeps.parseFlavor('')
-        platFlv = self.getPlatformBaseFlavor()
-        if platFlv is not None:
-            nflv = conaryDeps.parseFlavor(platFlv)
-            flv = conaryDeps.overrideFlavor(flv, nflv)
-        if self.baseFlavor is not None:
-            nflv = conaryDeps.parseFlavor(self.baseFlavor)
-            flv = conaryDeps.overrideFlavor(flv, nflv)
-        return str(flv)
-
-    def getStages(self):
-        """
-        @return: the stages from this product definition
-        @rtype: C{list} of C{_Stage} objects
-        """
-        return self.stages
-
-    def getStage(self, stageName):
-        """
-        Returns a C{_Stage} object for the given stageName.
-        @return: the C{_Stage} object for stageName
-        @rtype: C{_Stage} or C{None} if not found
-        @raises StageNotFoundError: if no such stage exists
-        """
-        ret = None
-        stages = self.getStages()
-        for stage in stages:
-            if stage.name == stageName:
-                return stage
-        raise StageNotFoundError(stageName)
-
-    def addStage(self, name = None, labelSuffix = None, promoteMaps = None):
-        """
-        Add a stage.
-        @param name: the stage's name
-        @type name: C{str} or C{None}
-        @param labelSuffix: Label suffix (e.g. '-devel') for the stage
-        @type labelSuffix: C{str} or C{None}
-        @param promoteMaps: list of promote maps for the stage
-        @type promoteMaps: C{list} of C{(mapName, mapLabel)} tuples
-        """
-        obj = _Stage(name = name, labelSuffix = labelSuffix,
-            promoteMaps = promoteMaps)
-        self.stages.append(obj)
-
-    def clearStages(self):
-        """
-        Delete all stages.
-        @return: None
-        @rtype None
-        """
-        self.stages = _Stages()
-
-    def getLabelForStage(self, stageName):
-        """
-        Synthesize the label for a particular stage based upon
-        the existing product information. Raises an exception
-        if there isn't enough information in the product definition
-        object to create the label.
-        @return: a Conary label string where for the given stage
-        @rtype: C{str}
-        @raises StageNotFoundError: if no such stage exists
-        @raises MissingInformationError: if there isn't enough information
-            in the product definition to generate the label
-        """
-        return self._getLabelForStage(self.getStage(stageName))
-
-    def getDefaultLabel(self):
-        """
-        Return the default label for commits.
-        @return: a label string representing the default label for this
-            product definition
-        @rtype: C{str}
-        @raises StageNotFoundError: if no such stage exists
-        @raises MissingInformationError: if there isn't enough information
-            in the object to generate the default label
-        """
-        # TODO: Currently, this is the development stage's label,
-        #       i.e. the one with suffix '-devel'.
-        #
-        #       Eventually the XML schema will explicitly define the
-        #       default label, either via a 'default' attribute on
-        #       the stage or via the stage's order.
-        ret = None
-        stages = self.getStages()
-        for stage in stages:
-            if stage.labelSuffix == '-devel':
-                return self._getLabelForStage(stage)
-        raise StageNotFoundError
-
-    def getSecondaryLabelsForStage(self, stageName):
-        """
-        @param stageName: A stage name
-        @type stageName: C{str}
-        @return: all secondary labels for the specified stage.
-        @rtype: C{list} of (name, value) tuples
-        """
-        stageObj = self.getStage(stageName)
-        if self.secondaryLabels is None:
-            return []
-        prefix = self.getProductDefinitionLabel()
-        labelSuffix = stageObj.labelSuffix or '' # this can be blank
-
-        ret = []
-        for sl in self.secondaryLabels:
-            name = sl.getName()
-            label = sl.getLabel()
-            fullLabel = self._getSecondaryLabel(label, labelSuffix)
-            ret.append((name, fullLabel))
-        return ret
-
-    def getPromoteMapsForStages(self, fromStage, toStage, flattenLabels=()):
-        """
-        Construct a promote map from C{fromStage} to C{toStage}.
-
-        This will include the "simple" label, all secondary labels, and
-        all promote maps to C{toStage}. All implicit promotes (primary
-        label, secondary labels, and flattened labels) are re-rooted at
-        the new label rather than preserving any shadows.
-
-        @param fromStage: Name of stage to promote I{from}
-        @type  fromStage: C{str}
-        @param toStage: Name of stage to promote I{to}
-        @type  toStage: C{str}
-        @param flattenLabels: Extra labels to "flatten" by promoting to the
-                              target label.
-        @type  flattenLabels: C{sequence or set}
-        @return: dictionary mapping labels on C{fromStage} to labels
-            on C{toStage}
-        @rtype: C{dict}
-        """
-        fromStageObj = self.getStage(fromStage)
-        toStageObj = self.getStage(toStage)
-        toStageBranch = '/' + self._getLabelForStage(toStageObj)
-
-        # Flattened labels - these come first so proddef-supplied maps 
-        # will override them.
-        fromTo = dict.fromkeys(flattenLabels, toStageBranch)
-
-        # Primary label
-        fromTo[self._getLabelForStage(fromStageObj)] = toStageBranch
-
-        # Secondary labels
-        if self.secondaryLabels is not None:
-            fromSuffix = fromStageObj.labelSuffix
-            toSuffix = toStageObj.labelSuffix
-            for secondaryLabel in self.secondaryLabels:
-                label = secondaryLabel.getLabel()
-                fromLabel = self._getSecondaryLabel(label, fromSuffix)
-                toLabel = self._getSecondaryLabel(label, toSuffix)
-                fromTo[fromLabel] = '/' + toLabel
-
-        # Promote maps
-        promoteMapsDest = dict((x.getMapName(), x.getMapLabel())
-            for x in toStageObj.getPromoteMaps())
-        for pm in fromStageObj.getPromoteMaps():
-            mapName = pm.getMapName()
-            if mapName not in promoteMapsDest:
-                continue
-            fromTo[pm.getMapLabel()] = promoteMapsDest[mapName]
-
-        return fromTo
-
-    def getSearchPaths(self):
-        """
-        @return: the search paths from this product definition
-        @rtype: C{list} of C{_SearchPath} objects
-        """
-        if self.searchPaths:
-            return self.searchPaths
-        return self.getPlatformSearchPaths()
-
-    def getResolveTroves(self):
-        """
-        @return: the search paths from this product definition, filtering
-                 any results that have isResolveTrove set to false. This
-                 is a subset of the results from getSearchPaths
-        @rtype: C{list} of C{_SearchPath} objects
-        """
-        if self.searchPaths:
-            searchPaths = self.searchPaths
-        else:
-            searchPaths = self.getPlatformSearchPaths()
-        if searchPaths:
-            searchPaths = [x for x in searchPaths 
-                           if x.isResolveTrove or x.isResolveTrove is None]
-        return searchPaths
-
-    def getGroupSearchPaths(self):
-        """
-        @return: the search paths from this product definition, filtering
-                 any results that have the isGroupSearchPathTrove attribute
-                 set to False. This is a subset of the results from 
-                 getSearchPaths
-        @rtype: C{list} of C{_SearchPath} objects
-        """
-        if self.searchPaths:
-            searchPaths = self.searchPaths
-        else:
-            searchPaths = self.getPlatformSearchPaths()
-        if searchPaths:
-            searchPaths = [x for x in searchPaths 
-                           if x.isGroupSearchPathTrove 
-                              or x.isGroupSearchPathTrove is None]
-        return searchPaths
-
-    def getFactorySources(self):
-        """
-        @return: the factory sources from this product definition
-        @rtype: C{list} of C{_FactorySource} objects
-        """
-        if self.factorySources:
-            return self.factorySources
-        return self.getPlatformFactorySources()
-
-    def getBuildDefinitions(self):
-        """
-        @return: The build definitions from this product definition
-        @rtype: C{list} of C{Build} objects
-        """
-        return self.buildDefinition
-
-    def addBuildDefinition(self, name = None, image = None, stages = None,
-                           imageGroup = None, sourceGroup = None, 
-                           architectureRef = None,
-                           containerTemplateRef = None, buildTemplateRef = None,
-                           flavorSetRef = None, flavor = None):
-        """
-        Add a build definition.
-        Image types are specified by calling C{ProductDefinition.imageType}.
-        Note that the usage of baseFlavor is deprecated in favor of using
-        references to architectures and image templates.
-        @param name: the name for the build definition
-        @type name: C{str} or C{None}
-        @param image: an image type, as returned by
-        C{ProductDefinition.imageType}.
-        @type image: an instance of an C{imageTypes.ImageType_Base}
-        @param stages: Stages for which to build this image type
-        @type stages: C{list} of C{str} referring to a C{_Stage} object's name
-        @param imageGroup: An optional image group that will override the
-        product definition's image group
-        @type imageGroup: C{str}
-        @param sourceGroup: An optional source group that will override the
-        product definition's source group
-        @type sourceGroup: C{str}
-        @param architectureRef: the name of an architecture to inherit flavors
-        from.
-        @type architectureRef: C{str}
-        @param containerTemplateRef: the name of the containerTemplate for
-        this image. This value overrides the value implied by the
-        buildTemplateRef, if supplied.
-        @type containerTemplateRef: C{str}
-        @param buildTemplateRef: the name of the buildTemplate to derive values
-        for containerTemplateRef and architectureRef.
-        @type: buildTemplateRef: C{str}
-        @param flavorSetRef: the name of the flavorSet to use for this image
-        @type: flavorSetRef: C{str}
-        @param flavor: additional flavors
-        @type flavor: C{str}
-        """
-        if architectureRef:
-            # Make sure we have the architecture
-            arch = self.getArchitecture(architectureRef, None)
-            if not arch:
-                self.getPlatformArchitecture(architectureRef)
-        if containerTemplateRef:
-            # make sure we have the containerTemplate
-            tmpl = self.getContainerTemplate(containerTemplateRef, None)
-            if not tmpl:
-                self.getPlatformContainerTemplate(containerTemplateRef)
-        if flavorSetRef:
-            # make sure we have the flavorSet
-            fs = self.getFlavorSet(flavorSetRef, None)
-            if not fs:
-                self.getPlatformFlavorSet(flavorSetRef)
-
-        obj = Build(name = name, image = image, stages = stages,
-                imageGroup = imageGroup,
-                sourceGroup = sourceGroup,
-                parentImageGroup = self.imageGroup,
-                parentSourceGroup = self.sourceGroup,
-                architectureRef = architectureRef,
-                containerTemplateRef = containerTemplateRef,
-                flavorSetRef = flavorSetRef,
-                buildTemplateRef = buildTemplateRef,
-                proddef = self, flavor = flavor)
-        self.buildDefinition.append(obj)
-
-    def clearBuildDefinition(self):
-        """
-        Delete all buildDefinition.
-        @return: None
-        @rtype None
-        """
-        self.buildDefinition = _BuildDefinition()
-
-    def getPlatformSearchPaths(self):
-        """
-        @return: the search paths from this product definition
-        @rtype: C{list} of C{_SearchPath} objects
-        """
-        if self.platform is None:
-            return []
-        return self.platform.searchPaths
-
-    def clearPlatformSearchPaths(self):
-        """
-        Delete all searchPaths.
-        @return: None
-        @rtype None
-        """
-        if self.platform is None:
-            return
-        self.platform.searchPaths = _SearchPaths()
-
-    def addPlatformSearchPath(self, troveName = None, label = None,
-                              version = None, isResolveTrove = True,
-                              isGroupSearchPathTrove = True):
-        """
-        Add an search path.
-        @param troveName: the trove name for the search path.
-        @type troveName: C{str} or C{None}
-        @param label: Label for the search path
-        @type label: C{str} or C{None}
-        @param version: Version for the search path
-        @param version: C{str} or C{None}
-        @param isResolveTrove: set to False if this element should be not
-               be returned for getResolveTroves()  (defaults to True)
-        @param isGroupSearchPathTrove: set to False if this element should be 
-               not be returned for getGroupSearchPath() (defaults to True)
-        """
-        if self.platform is None:
-            self.platform = PlatformDefinition()
-        self._addSource(troveName, label, version, _SearchPath,
-                        self.platform.searchPaths,
-                        isResolveTrove = isResolveTrove,
-                        isGroupSearchPathTrove = isGroupSearchPathTrove)
-
-    def getPlatformFactorySources(self):
-        """
-        @return: the factory sources from this product definition
-        @rtype: C{list} of C{_FactorySource} objects
-        """
-        if self.platform is None:
-            return []
-        return self.platform.factorySources
-
-    def clearPlatformFactorySources(self):
-        """
-        Delete all factorySources.
-        @return: None
-        @rtype None
-        """
-        if self.platform is None:
-            return
-        self.platform.factorySources = _FactorySources()
-
-    def addPlatformFactorySource(self, troveName = None, label = None,
-                                 version = None):
-        """
-        Add a factory source.
-        @param troveName: the trove name for the factory source.
-        @type troveName: C{str} or C{None}
-        @param label: Label for the factory source
-        @type label: C{str} or C{None}
-        @param version: Version for the factory source
-        @param version: C{str} or C{None}
-        """
-        if self.platform is None:
-            self.platform = PlatformDefinition()
-        self._addSource(troveName, label, version, _FactorySource,
-                        self.platform.factorySources)
-
-    def getPlatformName(self):
-        """
-        @return: The platform name.
-        @rtype: C{str}
-        """
-        if self.platform is None:
-            return None
-        return self.platform.getPlatformName()
-
-    def setPlatformName(self, platformName):
-        """
-        Set the platform name.
-        @param platformName: The platform name.
-        @type platformName: C{str}
-        """
-        self._ensurePlatformExists()
-        self.platform.setPlatformName(platformName)
-
-    def getPlatformVersionTrove(self):
-        """
-        @return: the platform version trove.
-        @rtype: C{str}
-        """
-        if self.platform is None:
-            return None
-        return self.platform.getPlatformVersionTrove()
-
-    def setPlatformVersionTrove(self, troveSpec):
-        """
-        Set the platform version trove.
-        @param troveSpec: The platfrm version trove
-        @type platformName: C{str}
-        """
-        self._ensurePlatformExists()
-        self.platform.setPlatformVersionTrove(troveSpec)
-
-    def getPlatformAutoLoadRecipes(self):
-        """
-        @return: auto load recipes.
-        @rtype: C{list} of C{AutoLoadRecipe}
-        """
-        if self.platform is None:
-            return []
-        return self.platform.getAutoLoadRecipes()
-
-    def addPlatformAutoLoadRecipe(self, troveName, label):
-        """
-        Add an auto load recipe
-        @param troveName: Trove name
-        @type troveName: C{str}
-        @param label: Label for the trove
-        @type label: C{str}
-        """
-        self._ensurePlatformExists()
-        self.platform.addAutoLoadRecipe(troveName, label)
-
-    def clearPlatformAutoLoadRecipes(self):
-        """
-        Clear the list of auto load recipes for the platform
-        """
-        if self.platform is None:
-            return
-        self.platform.clearAutoLoadRecipes()
-        return self
-
-    def getPlatformBaseFlavor(self):
-        """
-        @return: the platform's base flavor
-        @rtype: C{str}
-        """
-
-        if self.platform is None:
-            return None
-        return self.platform.baseFlavor
-
-    def setPlatformBaseFlavor(self, baseFlavor):
-        """
-        Set the platform's base flavor.
-        @param baseFlavor: A flavor for the platform.
-        @type baseFlavor: C{str}
-        """
-        self._ensurePlatformExists()
-        self.platform.baseFlavor = baseFlavor
-
-    def getPlatformSourceTrove(self):
-        """
-        @return: the source trove the for platform
-        @rtype: C{str}
-        """
-        if self.platform is None:
-            return None
-        return self.platform.sourceTrove
-
-    def setPlatformSourceTrove(self, sourceTrove):
-        """
-        Set the platform's source trove.
-        @param sourceTrove: the source trove name for the platform
-        @type sourceTrove: C{str}
-        """
-        self._ensurePlatformExists()
-        self.platform.sourceTrove = sourceTrove
-
-    def getPlatformUseLatest(self):
-        """
-        @return: the platform's useLatest flag.
-        @rtype: C{bool} or None
-        """
-        if self.platform is None:
-            return None
-        return self.platform.useLatest
-
-    def setPlatformUseLatest(self, useLatest):
-        """
-        Set the platform's useLatest flag.
-        @param useLatest: value for useLatest flag
-        @type useLatest: C{bool}
-        """
-        self._ensurePlatformExists()
-        self.platform.useLatest = useLatest
-
-    def getPlatformArchitecture(self, name, default = -1):
-        """
-        Retrieve the architecture with the specified name from the platform.
-        @param name: architecture name
-        @type name: C{str}
-        @param default: if an architecture with this name is not found, return
-        this value. If not specified, C{ArchitectureNotFoundError} is raised.
-        @rtype: Architecture object
-        @raises C{ArchitectureNotFoundError}: if architecture is not found, and
-        no default was specified.
-        """
-        pa = None
-        if self.platform:
-            pa = self.platform.getArchitecture(name, None)
-        if pa is not None or default != -1:
-            return pa
-        raise ArchitectureNotFoundError(name)
-
-    def getPlatformFlavorSet(self, name, default = -1):
-        """
-        Retrieve the flavorSet with the specified name from the platform.
-        @param name: flavorSet name
-        @type name: C{str}
-        @param default: if a flavorSet with this name is not found, return
-        this value. If not specified, C{FlavorSetNotFoundError} is raised.
-        @rtype: FlavorSet object
-        @raises C{FlavorSetNotFoundError}: if flavorSet is not found, and
-        no default was specified.
-        """
-        pa = None
-        if self.platform:
-            pa = self.platform.getFlavorSet(name, None)
-        if pa is not None or default != -1:
-            return pa
-        raise FlavorSetNotFoundError(name)
-
-    def getPlatformContainerTemplate(self, containerFormat, default = -1):
-        """
-        Retrieve the containerTemplate with the specified containerFormat from the platform.
-        @param containerFormat: containerTemplate containerFormat
-        @type containerFormat: C{str}
-        @param default: if a containerTemplate with this containerFormat is not found, return
-        this value. If not specified, C{ContainerTemplateNotFoundError} is raised.
-        @rtype: ContainerTemplate object
-        @raises C{ContainerTemplateNotFoundError}: if containerTemplate is not found, and
-        no default was specified.
-        """
-        pa = None
-        if self.platform:
-            pa = self.platform.getContainerTemplate(containerFormat, None)
-        if pa is not None or default != -1:
-            return pa
-        raise ContainerTemplateNotFoundError(containerFormat)
-
-    def getPlatformBuildTemplate(self, name, default = -1):
-        """
-        Retrieve the buildTemplate with the specified name from the platform.
-        @param name: buildTemplate name
-        @type name: C{str}
-        @param default: if a buildTemplate with this name is not found, return
-        this value. If not specified, C{BuildTemplateNotFoundError} is raised.
-        @rtype: BuildTemplate object
-        @raises C{BuildTemplateNotFoundError}: if buildTemplate is not found, and
-        no default was specified.
-        """
-        pa = None
-        if self.platform:
-            pa = self.platform.getBuildTemplate(name, None)
-        if pa is not None or default != -1:
-            return pa
-        raise BuildTemplateNotFoundError(name)
-
-    def addSecondaryLabel(self, name, label):
-        """
-        Add a secondary label to the product definition.
-        @param name: Name for the secondary label
-        @type name: C{str}
-        @param label: Label for the secondary label
-        @type label: C{str}
-        """
-        if self.secondaryLabels is None:
-            self.secondaryLabels = _SecondaryLabels()
-        self.secondaryLabels.append(SecondaryLabel(name, label))
-        return self
-
-    def getSecondaryLabels(self):
-        """
-        @return: the seconary labels for this product definition.
-        @rtype: C{list}
-        """
-        if self.secondaryLabels is None:
-            return []
-        return self.secondaryLabels
-
-    def clearSecondaryLabels(self):
-        """
-        Reset secondary label list.
-        """
-        self.secondaryLabels = None
-
-    def _ensurePlatformExists(self):
-        if self.platform is None:
-            self.platform = PlatformDefinition()
-
-    @classmethod
-    def imageType(cls, name, fields = None):
-        """
-        Image type factory. Given an image type name, it will instantiate an
-        object of the proper type.
-        @param name: The name of the image type.
-        @type name: C{str}
-        @param fields: Fields to initialize the image type object
-        @type fields: C{dict}
-        """
-        fields = fields or {}
-        if name is not None:
-            fields.setdefault('containerFormat', name)
-        return imageTypes.Image(fields)
-
-    def getBuildsForStage(self, stageName):
-        """
-        Retrieve all build definitions for a stage name.
-        @param stageName: stage name
-        @type stageName: C{str}
-        @return: A list of build definitions for the stage.
-        @rtype: C{list} of C{Build} objects
-        """
-        ret = []
-        for build in self.getBuildDefinitions():
-            if stageName in build.stages:
-                ret.append(build)
-        return ret
-
-    def setBaseLabel(self, label):
-        """
-        Set the base label for this product definition.
-        @param label: Value for the base label.
-        @type label: C{str}
-        """
-        self.baseLabel = label
-
-    def getBaseLabel(self):
-        """
-        @return: the base label for this product definition.
-        @rtype: C{str}
-        """
-        return self.baseLabel
-
-    def getProductDefinitionLabel(self):
-        """
-        Method that returns the product definition's label
-        @return: a Conary label string
-        @rtype: C{str}
-        @raises MissingInformationError: if there isn't enough information
-            in the product definition to generate the label
-        """
-        if self.baseLabel is not None:
-            return self.baseLabel
-
-        hostname = self.getConaryRepositoryHostname()
-        shortname = self.getProductShortname()
-        namespace = self.getConaryNamespace()
-        version = self.getProductVersion()
-
-        if not (hostname and shortname and namespace and version):
-            raise MissingInformationError
-        return str("%s@%s:%s-%s" % (hostname, namespace, shortname, version))
-
-    @classmethod
-    def getTroveName(cls):
-        """
-        @return: The name of the trove containing the product definition XML
-        file.
-        @rtype: C{str}
-        """
-        return cls._troveName
-
-    #{ Internal methods
-    def _getLabelForStage(self, stageObj):
-        """
-        Private method that works similarly to L{getLabelForStage},
-        but works on a given C{_Stage} object.
-        @return: a Conary label string where for the given stage object
-        @rtype: C{str}
-        @raises MissingInformationError: if there isn't enough information
-            in the product definition to generate the label
-        """
-        prefix = self.getProductDefinitionLabel()
-        labelSuffix = stageObj.labelSuffix or '' # this can be blank
-        return str(prefix + labelSuffix)
-
-    def toPlatformDefinition(self):
-        "Create a PlatformDefinition object from this ProductDefinition"
-        nplat = PlatformDefinition()
-        baseFlavor = self.getBaseFlavor()
-        nplat.setBaseFlavor(baseFlavor)
-
-        # Factory sources defined in the product defintion take precedence
-        fSources = self.getFactorySources()
-        for fsrc in fSources or []:
-            nplat.addFactorySource(troveName = fsrc.troveName,
-                                   label = fsrc.label)
-
-        # Build new search path
-        label = self.getProductDefinitionLabel()
-        sPathsList = []
-        sPathsSet = set()
-
-        # Iterate over all builds, and add the image group
-        for build in self.buildDefinition:
-            if not build.imageGroup:
-                continue
-            key = (build.imageGroup, label, tuple())
-            if key not in sPathsSet:
-                sPathsList.append(key)
-                sPathsSet.add(key)
-        # Append the global image group
-        key = (self.getImageGroup(), label, tuple())
-        if key not in sPathsSet:
-            sPathsList.append(key)
-            sPathsSet.add(key)
-        # Now append the search paths from this object, if available, or from
-        # the upstream platform, if available
-
-        # We are purposely dropping the versions from the platform definition
-        # on creation.
-
-        sPaths = self.getSearchPaths()
-        for sp in sPaths or []:
-            attrs = []
-            for key in ('isResolveTrove', 'isGroupSearchPathTrove'):
-                val = sp.__getattribute__(key)
-                if val is not None:
-                    attrs.append((key, val))
-            key = (sp.troveName, sp.label, tuple(attrs))
-            if key not in sPathsSet:
-                sPathsList.append(key)
-                sPathsSet.add(key)
-
-        for troveName, label, attrs in sPathsList:
-            nplat.addSearchPath(troveName=troveName, label=label, **dict(attrs))
-
-        for arch in self.getArchitectures():
-            nplat.addArchitecture(name = arch.name,
-                    displayName = arch.displayName, flavor = arch.flavor)
-
-        for flvSet in self.getFlavorSets():
-            nplat.addFlavorSet(name = flvSet.name,
-                    displayName = flvSet.displayName, flavor = flvSet.flavor)
-
-        for ctmpl in self.getContainerTemplates():
-            nplat.addContainerTemplate(ctmpl)
-
-        for btmpl in self.getBuildTemplates():
-            nplat.addBuildTemplate(name = btmpl.name,
-                    displayName = btmpl.displayName,
-                    architectureRef = btmpl.architectureRef,
-                    containerTemplateRef = btmpl.containerTemplateRef,
-                    flavorSetRef = btmpl.flavorSetRef,)
-
-        nplat.setPlatformName(self.getPlatformName())
-        nplat.setPlatformVersionTrove(self.getPlatformVersionTrove())
-
-        for alr in self.getPlatformAutoLoadRecipes():
-            nplat.addAutoLoadRecipe(alr.getTroveName(), alr.getLabel())
-
-        return nplat
-
-    def savePlatformToRepository(self, client, message = None):
-        nplat = self.toPlatformDefinition()
-        label = self.getProductDefinitionLabel()
-        nplat.saveToRepository(client, label, message = message)
-
-    def rebase(self, client, label = None, useLatest = None):
-        if label is None:
-            troveSpec = self.getPlatformSourceTrove()
-            if troveSpec:
-                tn, tv, tf = cmdline.parseTroveSpec(troveSpec)
-                if not tv.startswith('/'):
-                    tv = "/" + tv
-                label = str(conaryVersions.VersionFromString(tv).trailingLabel())
-            else:
-                label = None
-        if label is None:
-            raise PlatformLabelMissingError()
-        nplat = self.toPlatformDefinition()
-        nplat.loadFromRepository(client, label)
-        nplat.snapshotVersions(client)
-        self._rebase(label, nplat, useLatest = useLatest)
-
-    def _rebase(self, label, nplat, useLatest = None):
-        # Create a new platform definition
-        self.platform = PlatformDefinition()
-        # Fill it in with fields from the upstream one
-        self.setPlatformBaseFlavor(nplat.getBaseFlavor())
-        self.setPlatformSourceTrove(nplat.sourceTrove)
-        self.setPlatformUseLatest(useLatest)
-        self.platform.setPlatformName(nplat.getPlatformName())
-        self.platform.setPlatformVersionTrove(nplat.getPlatformVersionTrove())
-        for alr in nplat.getAutoLoadRecipes():
-            self.addPlatformAutoLoadRecipe(troveName = alr.getTroveName(),
-                    label = alr.getLabel())
-        for sp in nplat.getSearchPaths():
-            self.addPlatformSearchPath(troveName=sp.troveName,
-                               label=sp.label,
-                               version=sp.version,
-                               isResolveTrove=sp.isResolveTrove,
-                               isGroupSearchPathTrove=sp.isGroupSearchPathTrove)
-        for fs in nplat.getFactorySources():
-            self.addPlatformFactorySource(troveName=fs.troveName,
-                                          label=fs.label,
-                                          version=fs.version)
-        for item in nplat.getArchitectures():
-            self.platform.addArchitecture(name = item.name,
-                                          displayName = item.displayName,
-                                          flavor = item.flavor)
-        for flvSet in nplat.getFlavorSets():
-            self.platform.addFlavorSet(name = flvSet.name,
-                    displayName = flvSet.displayName, flavor = flvSet.flavor)
-
-        for image in nplat.getContainerTemplates():
-            self.platform.addContainerTemplate(image)
-
-        for btmpl in nplat.getBuildTemplates():
-            self.platform.addBuildTemplate(name = btmpl.name,
-                    displayName = btmpl.displayName,
-                    architectureRef = btmpl.architectureRef,
-                    containerTemplateRef = btmpl.containerTemplateRef,
-                    flavorSetRef = btmpl.flavorSetRef)
-
-    def _getSecondaryLabel(self, label, suffix):
-        """
-        Given a label from C{secondaryStages} and a C{suffix},
-        construct a complete "secondary" label.
-
-        @param label: Base label from C{secondaryStages} to use as
-            a prefix
-        @type  label: C{str}
-        @param suffix: Suffix to append to base label
-        @type  suffix: C{str}
-        @return: constructed secondary label
-        @rtype: C{str}
-        """
-        if '@' in label:
-            # Just append the stage suffix
-            return str(label + suffix)
-        else:
-            # Use the entire product label
-            prefix = self.getProductDefinitionLabel()
-            return str(prefix + label + suffix)
-
-    def _initFields(self):
-        BaseDefinition._initFields(self)
-        self.stages = _Stages()
-        self.productName = None
-        self.productShortname = None
-        self.productDescription = None
-        self.productVersion = None
-        self.productVersionDescription = None
-        self.conaryRepositoryHostname = None
-        self.conaryNamespace = None
-        self.imageGroup = None
-        self.sourceGroup = None
-        self.baseLabel = None
-        self.buildDefinition = _BuildDefinition()
-        self.platform = None
-        self.secondaryLabels = None
-
-    #}
-
-
-class PlatformDefinition(BaseDefinition):
-    _troveName = 'platform-definition'
-
-    # list of files to search for in the trove, ordered by priority.
-    _troveFileNames = [
-        'platform-definition-3.0.xml',
-        'platform-definition.xml',
-    ]
-
-    _recipe = '''
-#
-# Copyright (c) 2008 rPath, Inc.
-#
-
-class PlatformDefinitionRecipe(PackageRecipe):
-    name = "@NAME@"
-    version = "@VERSION@"
-
-    def setup(r):
-        """
-        This recipe is a stub created to allow users to manually
-        check in changes to the product definition XML.
-
-        No other recipe actions need to be added beyond this point.
-        """
-'''
-
-    def _initFields(self):
-        BaseDefinition._initFields(self)
-        self.useLatest = None
-        self.sourceTrove = None
-        self.platformName = None
-        self.platformVersionTrove = None
-        self.autoLoadRecipes = None
-
-    def parseStream(self, stream, validate = False, schemaDir = None):
-        """
-        Initialize the current object from an XML stream.
-        @param stream: An XML stream
-        @type stream: C{file}
-        @param validate: Validate before parsing (off by default)
-        @type validate: C{bool}
-        @param schemaDir: A directory where schema files are stored
-        @type schemaDir: C{str}
-        """
-        self._initFields()
-        binder = xmllib.DataBinder()
-        binder.registerType(_PlatformDefinition, 'platformDefinition')
-        xmlObj = binder.parseFile(stream, validate = validate,
-                                  schemaDir = schemaDir or self.schemaDir)
-        self.baseFlavor = getattr(xmlObj.platform, 'baseFlavor', None)
-        self.sourceTrove = getattr(xmlObj.platform, 'sourceTrove', None)
-        self.useLatest = getattr(xmlObj.platform, 'useLatest', None)
-        self.searchPaths = getattr(xmlObj.platform, 'searchPaths', None)
-        self.factorySources = getattr(xmlObj.platform, 'factorySources', None)
-        self.architectures = getattr(xmlObj.platform, 'architectures', None)
-        self.flavorSets = getattr(xmlObj.platform, 'flavorSets', None)
-        self.containerTemplates = getattr(xmlObj.platform, 'containerTemplates', None)
-        self.buildTemplates = getattr(xmlObj.platform, 'buildTemplates', None)
-        self.platformName = getattr(xmlObj.platform, 'platformName', None)
-        self.platformVersionTrove = getattr(xmlObj.platform, 'platformVersionTrove', None)
-        self.autoLoadRecipes = getattr(xmlObj.platform, 'autoLoadRecipes', None)
-
-        for nsName, nsVal in xmlObj.iterNamespaces():
-            if nsName is None and nsVal != self.defaultNamespace:
-                self.defaultNamespace = nsVal
-                continue
-            # XXX We don't support changing the schema location for now
-
-    def serialize(self, stream):
-        """
-        Serialize the current object as an XML stream.
-        @param stream: stream to write the serialized object
-        @type stream: C{file}
-        """
-        attrs = {'version' : self.version,
-                 'xmlns' : self.defaultNamespace,
-                 'xmlns:xsi' : xmllib.DataBinder.xmlSchemaNamespace,
-                 "xsi:schemaLocation" : self.xmlSchemaLocation,
-        }
-        nameSpaces = {}
-        serObj = _PlatformSerialization(attrs, nameSpaces, self,
-            name="platformDefinition")
-        binder = xmllib.DataBinder()
-        stream.write(binder.toXml(serObj))
-
-    def saveToRepository(self, client, label, message = None):
-        """
-        Save a C{PlatformDefinition} object to a Conary repository.
-        @param client: A Conary client object
-        @type client: C{conaryclient.ConaryClient}
-        @param message: An optional commit message
-        @type message: C{str}
-        @param label: Label where the representation will be saved
-        @type label: C{str}
-        """
-        return self._saveToRepository(client, label, message = message)
-
-    def loadFromRepository(self, client, label):
-        """
-        Load a C{PlatformDefinition} object from a Conary repository.
-        @param client: A Conary client object
-        @type client: C{conaryclient.ConaryClient}
-        @raises C{RepositoryError}:
-        @raises C{ProductDefinitionTroveNotFoundError}:
-        @raises C{ProductDefinitionFileNotFoundError}:
-        """
-        stream, nvf = self._getStreamFromRepository(client, label)
-        stream.seek(0)
-        self.parseStream(stream)
-        # Set the source trove version we used
-        self.sourceTrove = "%s=%s" % (self._troveName, nvf[1])
-
-    def snapshotVersions(self, conaryClient):
-        """
-        For each search path or factory source from this platform definition,
-        query the repositories for the latest versions and record them.
-        @param conaryClient: A Conary client object
-        @type conaryClient: C{conaryclient.ConaryClient}
-        """
-        repos = conaryClient.getRepos()
-        troveSpecs = set()
-        # XXX We are ignoring the flavors for now.
-        for sp in itertools.chain(self.getSearchPaths(),
-                                  self.getFactorySources()):