[Zope-CVS] SVN: zpkgtools/trunk/ Split the zpkgtools Python package into two packages:

Fred L. Drake, Jr. fred at zope.com
Thu Jun 17 12:12:11 EDT 2004


Log message for revision 25887:
Split the zpkgtools Python package into two packages:
a build/install runtime component (zpkgsetup) and a distribution builder
component (zpkgtools).
This helps keep the size of the code added to a distribution small.



-=-
Modified: zpkgtools/trunk/bin/zpkg
===================================================================
--- zpkgtools/trunk/bin/zpkg	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/bin/zpkg	2004-06-17 16:12:11 UTC (rev 25887)
@@ -25,8 +25,9 @@
     sys.path.append(basedir)
     import zpkgtools
 
+from zpkgsetup import loggingapi as logging
+
 from zpkgtools import app
-from zpkgtools import loggingapi as logging
 
 
 if __name__ == "__main__":

Modified: zpkgtools/trunk/doc/zpkg.txt
===================================================================
--- zpkgtools/trunk/doc/zpkg.txt	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/doc/zpkg.txt	2004-06-17 16:12:11 UTC (rev 25887)
@@ -60,7 +60,7 @@
 -S
   Don't include the required support packages in the distribution.
   This can be used to generate smaller distributions when the
-  ``setuptools`` and ``zpkgtools`` packages are known to be available
+  ``setuptools`` and ``zpkgsetup`` packages are known to be available
   on target systems.
 
 -v VERSION
@@ -97,7 +97,7 @@
 bundles the support code along with the resulting distribution.  The
 value is a boolean, where the strings ``true`` and ``false`` can be
 used in the configuration file.  If true (the default), copies of the
-``zpkgtools`` and ``setuptools`` packages will be included in the
+``zpkgsetup`` and ``setuptools`` packages will be included in the
 distribution (less their test code).  If false, the packages will be
 assumed to be available for import on target systems.
 
@@ -217,8 +217,8 @@
 using a ``file:`` URL::
 
   setuptools  file:///home/myuser/stuff/setuptools/setuptools
-  zpkgtools   file:///home/myuser/stuff/zpkgtools/zpkgtools
+  zpkgsetup   file:///home/myuser/stuff/zpkgtools/zpkgsetup
 
 (The path should identify the directory that contains the
-``setuptools`` or ``zpkgtools`` package itself, not the directory that
+``setuptools`` or ``zpkgsetup`` package itself, not the directory that
 would be on ``sys.path`` to allow it to be importable.)

Modified: zpkgtools/trunk/test.py
===================================================================
--- zpkgtools/trunk/test.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/test.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -27,8 +27,16 @@
         print >>sys.stderr, \
               "arguments only supported when zope.app.tests is available"
         sys.exit(2)
-    from zpkgtools.tests import runtests
-    runtests.MyTestProgram(defaultTest="runtests.test_suite")
+
+    def test_suite():
+        from zpkgsetup.tests import runtests
+        suite = runtests.test_suite()
+        from zpkgtools.tests import runtests
+        suite.addTest(runtests.test_suite())
+        return suite
+
+    from zpkgsetup.tests import runtests
+    runtests.MyTestProgram(defaultTest="test_suite")
 else:
     # 1. search for tests in starting in this directory
     # 2. there are only unit tests, not functional tests

Added: zpkgtools/trunk/zpkgsetup/__init__.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/__init__.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgsetup/__init__.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,29 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Zope packaging utilities runtime support.
+
+:organization: Zope Corporation
+:license: `Zope Public License, Version 2.0 (ZPL)`__
+:status: Prototype implementation
+
+This package contains the build/install support for distributions
+built using the **zpkg** tool.
+
+.. __: http://www.zope.org/Resources/ZPL/ZPL-2.0
+
+"""
+
+
+class Error(Exception):
+    """Base class for exceptions raised by zpkgsetup."""


Property changes on: zpkgtools/trunk/zpkgsetup/__init__.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Copied: zpkgtools/trunk/zpkgsetup/cfgparser.py (from rev 25884, zpkgtools/trunk/zpkgtools/cfgparser.py)

Copied: zpkgtools/trunk/zpkgsetup/loggingapi.py (from rev 25884, zpkgtools/trunk/zpkgtools/loggingapi.py)

Copied: zpkgtools/trunk/zpkgsetup/package.py (from rev 25884, zpkgtools/trunk/zpkgtools/package.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/package.py	2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/package.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,518 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Support for handling package configuration files.
+
+The package configuration files handled by this module provide
+information about the software and documentation contents of a
+distribution component.  The same kinds of information can be
+described for any component, with the exception that extensions only
+make sense for package components.
+
+Package configuration files use a syntax very like the `ZConfig`_
+package, but fewer features are available.  The specific syntax is
+implemented by the `cfgparser` module.
+
+.. _ZConfig:  http://www.zope.org/Members/fdrake/zconfig/
+
+There are only a few types of information which can appear in a
+package configuration file; the file is intended to describe what a
+package provides that is not a module or data file.  The three types
+of things which can be listed in the file are:
+
+- scripts
+- documentation
+- extensions
+
+The scripts and documentation files are listed very simply::
+
+  documentation  *.txt
+  documentation  apiref.pdf
+
+  script  scritps/*
+
+The value to the right of the identifying keyword is a portable glob
+pattern, where *portable* here means the pattern uses the POSIX
+notation.  Path components should be separated by forward slashes
+(like all paths used with distutils), ``?`` can be replaced by any
+single character, and ``*`` can be replaced by zero or more
+characters.
+
+
+:Variables:
+  - `PACKAGE_CONF`:  Name of the package information file.
+
+:Groups:
+  - `Public interface`: loadCollectionInfo loadPackageInfo
+  - `Helper functions`: create_extension expand_globs read_package_info
+  - `Datatype functions`: cpp_definition cpp_names path_ref extension
+
+"""
+
+import glob
+import os
+import posixpath
+import re
+import urllib
+
+from distutils.core import Extension
+from StringIO import StringIO
+
+from zpkgsetup import cfgparser
+
+
+PACKAGE_CONF = "SETUP.cfg"
+
+
+def loadPackageInfo(pkgname, directory, reldir):
+    """Load package information for a Python package.
+
+    :return: Package information object.
+
+    :Parameters:
+      - `pkgname`: Full name of the Python package to which the
+        information being read applies.  This is needed to construct
+        Extension objects properly.
+      - `directory`: Directory containing the package's __init__.py file.
+      - `reldir`: Relative directory path with which file names from
+        the information file will be joined.  This should be in POSIX
+        notation.  It will not be used to locate files.
+
+    """
+    pkginfo = read_package_info(directory, reldir)
+    pkginfo.extensions = [create_extension(ext, pkgname, reldir)
+                          for ext in pkginfo.extension]
+    return pkginfo
+
+
+def loadCollectionInfo(directory, reldir):
+    """Load package information for a collection.
+
+    :return: Package information object.
+
+    :Parameters:
+      - `directory`: Directory containing the collection's files.
+      - `reldir`: Relative directory path with which file names from
+        the information file will be joined.  This should be in POSIX
+        notation.  It will not be used to locate files.
+
+    """
+    pkginfo = read_package_info(directory, reldir)
+    if pkginfo.extension:
+        raise ValueError("extensions cannot be defined in collections")
+    pkginfo.extensions = []
+    return pkginfo
+
+
+def read_package_info(directory, reldir=None):
+    """Read the package information file from a specified directory.
+
+    :return: Package information object.
+
+    :Parameters:
+      - `directory`: Directory containing the collection's files.
+      - `reldir`: Relative directory path with which file names from
+        the information file will be joined.  This should be in POSIX
+        notation.  It will not be used to locate files.  It may be
+        omitted or None; if so, filenames are not 'relocated' relative
+        to where they are found.
+
+    """
+    path = os.path.join(directory, PACKAGE_CONF)
+    if os.path.exists(path):
+        path = os.path.realpath(path)
+        url = "file://" + urllib.pathname2url(path)
+        f = open(path)
+    else:
+        # Initialize using the cfgparser so we still get a package
+        # data object with the right attributes:
+        url = "<no file>"
+        f = StringIO("")
+    try:
+        p = cfgparser.Parser(f, url, PackageSchema(directory, reldir))
+        pkginfo = p.load()
+    finally:
+        f.close()
+    pkginfo.documentation = expand_globs(directory, reldir,
+                                         pkginfo.documentation)
+    pkginfo.header = expand_globs(directory, reldir, pkginfo.header)
+    pkginfo.script = expand_globs(directory, reldir, pkginfo.script)
+
+    # need to post-process the data_files so included directories are
+    # handled properly; distutils expects everything to be a file!
+    #
+    # XXX need tests!
+    #
+    datamap = {}
+    for dir, paths in pkginfo.data_files:
+        expand_data(directory, reldir, dir, paths, datamap)
+    if "." in datamap and datamap["."] == []:
+        del datamap["."]
+    pkginfo.data_files = datamap.items()
+
+    return pkginfo
+
+
+def expand_data(directory, reldir, targetdir, paths, datamap):
+    #
+    # `directory` is where we find things
+    #
+    # `reldir` is the relative location of directory in the source; we
+    # need it so we can rip it off of the values in `paths`
+    #
+    # `targetdir` is where we want the things in `paths` copied in
+    # POSIX notation
+    #
+    # `paths` is a list of paths to things we want copied, in POSIX
+    # notation, with `reldir` prepended
+    #
+    # `datamap` is a mapping from target directory -> [files], where
+    # files are really paths to actual files (not directories!) that
+    # are to be copied to the target directory; the file paths are
+    # given in POSIX notation and are prefixed by `reldir`
+    #
+    # All directories must be represented in the data map, even if
+    # they're empty.
+    #
+    targetdir = posixpath.normpath(targetdir)
+
+    # Make sure there's an entry for every directory we look at; that
+    # ensures distutils will create empty directories for us.
+    L = datamap.setdefault(targetdir, [])
+
+    if reldir:
+        prefix = posixpath.join(reldir, "")
+    else:
+        prefix = ""
+
+    # for files, add to the list, otherwise recursively scan
+    for src in paths:
+        # strip `reldir`, convert to local path notation
+        localpath = src[len(prefix):].replace("/", os.sep)
+        # find the referenced path
+        fullpath = os.path.join(directory, localpath)
+        if os.path.isfile(fullpath):
+            L.append(src)
+        else:
+            # directory; recurse
+            basename = os.path.basename(fullpath)
+            expand_data(
+                directory, reldir, posixpath.join(targetdir, basename),
+                [posixpath.join(src, name) for name in os.listdir(fullpath)],
+                datamap)
+
+
+def create_extension(section, pkgname, reldir):
+    """Create an `Extension` instance from a configuration section.
+
+    :Parameters:
+      - `section`: Section object from the configuration file.
+      - `pkgname`: Full name of the containing package.  This should
+        be an empty string or ``None`` if the extension is not in a
+        package.
+      - `reldir`: Directory in which the extension lives, relative to
+        the top of the distribution, given in POSIX notation.
+
+    """
+    kwargs = {}
+    if pkgname:
+        kwargs["name"] = "%s.%s" % (pkgname, section.name)
+    else:
+        kwargs["name"] = section.name
+    kwargs["sources"] = [posixpath.join(reldir, fn)
+                         for fn in section.source]
+    if section.define:
+        kwargs["define_macros"] = section.define
+    if section.undefine:
+        kwargs["undef_macros"] = undefs = []
+        for L in section.undefine:
+            undefs.extend(L)
+    if section.depends_on:
+        kwargs["depends"] = [posixpath.join(reldir, fn)
+                             for fn in section.depends_on]
+    if section.language:
+        kwargs["language"] = section.language[0]
+    if reldir and reldir != ".":
+        kwargs["include_dirs"] = [reldir]
+    return Extension(**kwargs)
+
+
+def expand_globs(directory, reldir, globlist):
+    """Expand glob patterns for directory.
+
+    :Parameters:
+      - `directory`: The path to the directory to which the glob
+        patterns are relative to.
+      - `reldir`: Base directory to use for returning glob expansions.
+        This should be a relative path in POSIX notation.  This is not
+        used for locating files.
+      - `globlist`: List of glob patterns in POSIX notation.  The
+        patterns may refer to child directories of `directory`.
+
+    :return: List of expansions in POSIX notation, using `reldir` as
+      the base directory.
+
+    Note that `directory` and `reldir` are two different names for the
+    same directory.
+
+    :warning: This function is not thread safe, as it changes the
+      current working directory while it is running.
+
+    """
+    results = []
+    pwd = os.getcwd()
+    os.chdir(directory)
+    try:
+        for g in globlist:
+            gs = g.replace("/", os.sep)
+            filenames = glob.glob(gs)
+            if not filenames:
+                raise ValueError(
+                    "filename pattern %r doesn't match any files" % g)
+            filenames = [fn.replace(os.sep, "/") for fn in filenames]
+            if reldir:
+                filenames = [posixpath.join(reldir, fn) for fn in filenames]
+            results += filenames
+    finally:
+        os.chdir(pwd)
+    return results
+
+
+# datatype functions referenced by the schema:
+
+def cpp_definition(s):
+    r"""Return a 2-tuple representing a CPP #define.
+
+    :rtype: (str, str or None)
+
+    The first element of the tuple is the name to define, and the
+    second is the value to use as the replacement text.  In the input,
+    the two parts should be separated by an equal sign.
+
+    >>> cpp_definition('NAME=VALUE')
+    ('NAME', 'VALUE')
+    >>> cpp_definition('NAME=')
+    ('NAME', '')
+
+    Whitespace around the equal sign are ignored:
+
+    >>> cpp_definition('NAME   =\tVALUE')
+    ('NAME', 'VALUE')
+
+    If there is no equal sign, and defininition with no replacement
+    text is used (equivalent to '#define NAME'):
+
+    >>> cpp_definition('NAME')
+    ('NAME', None)
+
+    ValueError is raised if there is an error in the input:
+
+    >>> cpp_definition('not-a-cpp-symbol')
+    Traceback (most recent call last):
+      ...
+    ValueError: not a valid C identifier: 'not-a-cpp-symbol'
+
+    """
+    if "=" in s:
+        name, value = s.split("=", 1)
+        name = name.rstrip()
+        value = value.lstrip()
+    else:
+        name = s
+        value = None
+    if _cpp_ident_match(name) is None:
+        raise ValueError("not a valid C identifier: %r" % name)
+    return name, value
+
+
+def cpp_names(s):
+    r"""Return a list of CPP symbols from a string.
+
+    :rtype: [str, ...]
+
+    >>> cpp_names('NAME')
+    ['NAME']
+    >>> cpp_names('NAME1 NAME_2 A_B_C A123')
+    ['NAME1', 'NAME_2', 'A_B_C', 'A123']
+
+    If something is included which is not a valid identifier for CPP,
+    ValueError is raised:
+
+    >>> cpp_names('not-really!')
+    Traceback (most recent call last):
+      ...
+    ValueError: not a valid C identifier: 'not-really!'
+
+    >>> cpp_names('NAME ANOTHER not-really!')
+    Traceback (most recent call last):
+      ...
+    ValueError: not a valid C identifier: 'not-really!'
+
+    """
+    names = s.split()
+    for name in names:
+        if _cpp_ident_match(name) is None:
+            raise ValueError("not a valid C identifier: %r" % name)
+    return names
+
+_cpp_ident_match = re.compile("[A-Za-z_][A-Za-z_0-9]*$").match
+
+
+def extension(section):
+    """Transform `section`, checking several fields for valid values.
+
+    :param section: Configuration section.
+    :return: Modified section.
+    """
+    section.name = section.getSectionName()
+    if not section.name:
+        raise ValueError("extensions must be named")
+    if not section.source:
+        raise ValueError("at least one extension source file must be listed")
+    if len(section.language) > 1:
+        raise ValueError("language can only be specified once")
+    return section
+
+
+def path_ref(s):
+    """Datatype for a local path reference.
+
+    :rtype: str
+
+    >>> path_ref('README.txt')
+    'README.txt'
+    >>> path_ref('./README.txt')
+    'README.txt'
+    >>> path_ref('foo/bar/file.txt')
+    'foo/bar/file.txt'
+
+    If a reference is not a relative path, ValueError is raised:
+
+    >>> path_ref('/absolute/path')
+    Traceback (most recent call last):
+      ...
+    ValueError: absolute paths are not allowed: '/absolute/path'
+
+    >>> path_ref('/')
+    Traceback (most recent call last):
+      ...
+    ValueError: absolute paths are not allowed: '/'
+
+    References which contain Windows drive letters are not allowed:
+
+    >>> path_ref('c:README.txt')
+    Traceback (most recent call last):
+      ...
+    ValueError: Windows drive letters are not allowed: 'c:README.txt'
+
+    If a reference is relative but points outside the local directory
+    hierarchy, ValueError is raised:
+
+    >>> path_ref('../somefile')
+    Traceback (most recent call last):
+      ...
+    ValueError: relative paths may not point outside the containing tree: '../somefile'
+
+    """
+    if not s:
+        raise ValueError("path references may not be empty")
+    if s.find(":") == 1:
+        # looks like a windows drive letter:
+        raise ValueError("Windows drive letters are not allowed: %r" % s)
+    p = posixpath.normpath(s)
+    if p[:1] == "/":
+        raise ValueError("absolute paths are not allowed: %r" % s)
+    parts = p.split("/")
+    if parts[0] == "..":
+        raise ValueError("relative paths may not point outside"
+                         " the containing tree: %r" % s)
+    return p
+
+
+class PackageSchema(cfgparser.Schema):
+    """Schema implementation with a <data-files> section type.
+
+    The <data-files> sections have keys that are glob-expanded (based
+    on information passed to the constructor) and combined into a
+    single .data_files member on the resulting package information
+    object.  The value of the .data_files attribute is suitable for
+    passing to the distutils.core.setup() function.
+
+    """
+
+    def __init__(self, directory, reldir):
+        cfgparser.Schema.__init__(
+            self,
+            ({"script": path_ref,
+              "documentation": path_ref,
+              "header": path_ref},
+             ["extension"], None),
+            {"extension": ({"source": path_ref, "depends-on": path_ref,
+                            "define" : cpp_definition, "undefine": cpp_names,
+                            "language": str,
+                            },
+                           (), extension),
+             }
+            )
+        self.__cf = None
+        self.__datafiles = None
+        self.__directory = directory
+        self.__reldir = reldir
+
+    def getConfiguration(self):
+        assert self.__cf is None
+        self.__cf = cfgparser.Schema.getConfiguration(self)
+        self.__cf.data_files = []
+        return self.__cf
+
+    def startSection(self, parent, typename, name):
+        if self.__datafiles is not None:
+            raise cfgparser.ConfigurationError(
+                "can't nest another section inside <data-files> section")
+        if typename == "data-files":
+            if not name:
+                raise cfgparser.ConfigurationError(
+                    "<data-files> section must have a name")
+            normname = posixpath.normpath(name)
+            for target, files in self.__cf.data_files:
+                if target == normname:
+                    raise cfgparser.ConfigurationError(
+                        "can't have two sections of the same name:"
+                        " <data-files %s>" % name)
+            self.__datafiles = []
+            self.__cf.data_files.append((normname, self.__datafiles))
+            # The return value is passed around, but that's it
+            return ()
+        else:
+            return cfgparser.Schema.startSection(self, parent, typename, name)
+
+    def endSection(self, parent, typename, name, child):
+        if self.__datafiles is None:
+            cfgparser.Schema.endSection(self, parent, typename, name, child)
+        else:
+            # mutate self.__datafiles since the reference from
+            # self.__cf.data_files is what's actually used
+            self.__datafiles[:] = expand_globs(self.__directory,
+                                               self.__reldir,
+                                               self.__datafiles)
+            self.__datafiles = None
+
+    def addValue(self, section, key, value):
+        if self.__datafiles is not None:
+            if value:
+                raise cfgparser.ConfigurationError(
+                    "each entry in a <data-files> section must be"
+                    " a single glob pattern")
+            self.__datafiles.append(key)
+        else:
+            cfgparser.Schema.addValue(self, section, key, value)

Copied: zpkgtools/trunk/zpkgsetup/publication.py (from rev 25884, zpkgtools/trunk/zpkgtools/publication.py)

Copied: zpkgtools/trunk/zpkgsetup/setup.py (from rev 25884, zpkgtools/trunk/zpkgtools/setup.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/setup.py	2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/setup.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,245 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Generator for distutils setup.py files.
+
+:Variables:
+  - `EXCLUDE_NAMES`: Names of files and directories that will be
+    excluded from copying.  These are generally related to source
+    management systems, but don't need to be.
+
+  - `EXCLUDE_PATTERNS`: Glob patterns used to filter the set of files
+    that are copied.  Any file with a name matching these patterns
+    will be ignored.
+
+"""
+
+import errno
+import fnmatch
+import os
+import posixpath
+import re
+import sys
+
+from zpkgsetup import package
+from zpkgsetup import publication
+
+
+# Names that are exluded from globbing results:
+EXCLUDE_NAMES = ["CVS", ".cvsignore", "RCS", "SCCS", ".svn"]
+EXCLUDE_PATTERNS = ["*.py[cdo]", "*.s[ol]", ".#*", "*~"]
+
+def filter_names(names):
+    """Given a list of file names, return those names that should be copied.
+    """
+    names = [n for n in names
+             if n not in EXCLUDE_NAMES]
+    # This is needed when building a distro from a working
+    # copy (likely a checkout) rather than a pristine export:
+    for pattern in EXCLUDE_PATTERNS:
+        names = [n for n in names
+                 if not fnmatch.fnmatch(n, pattern)]
+    return names
+
+
+class SetupContext:
+    """Object representing the arguments to distutils.core.setup()."""
+
+    def __init__(self, pkgname, version, setup_file):
+        self._working_dir = os.path.dirname(os.path.abspath(setup_file))
+        self._pkgname = pkgname
+        self.version = version
+        self.packages = []
+        self.package_data = {}
+        self.package_dir = {}
+        self.ext_modules = []
+        self.scripts = []
+        self.platforms = None
+        self.classifiers = None
+        self.data_files = []
+
+    def initialize(self):
+        self.load_metadata(
+            os.path.join(self._working_dir, self._pkgname,
+                         publication.PUBLICATION_CONF))
+        pkgdir = os.path.join(self._working_dir, self._pkgname)
+        self.scan(self._pkgname, pkgdir, self._pkgname)
+        depsdir = os.path.join(self._working_dir, "Dependencies")
+        if os.path.isdir(depsdir):
+            depnames = os.listdir(depsdir)
+            suffix = "-%s-%s" % (self._pkgname, self.version)
+            for name in depnames:
+                if name != "Includes" and not name.endswith(suffix):
+                    # an unexpected name; we didn't put this here!
+                    print >>sys.stderr, \
+                          "unexpected name in Dependencies/: %r" % name
+                    continue
+                depdir = os.path.join(depsdir, name)
+                if not os.path.isdir(depdir):
+                    # a file; we didn't put this here either!
+                    print >>sys.stderr, \
+                          "unexpected file in Dependencies/: %r" % name
+                    continue
+                depname = name[:-len(suffix)]
+                pkgdir = os.path.join(depdir, depname)
+                reldir = posixpath.join("Dependencies", name, depname)
+                self.scan(depname, pkgdir, reldir)
+            includes_dir = os.path.join(depsdir, "Includes")
+            if os.path.isdir(includes_dir):
+                for ext in self.ext_modules:
+                    ext.include_dirs.append(includes_dir)
+
+    def setup(self):
+        kwargs = self.__dict__.copy()
+        for name in self.__dict__:
+            if name[0] == "_":
+                del kwargs[name]
+        if "--debug" in sys.argv:
+            import pprint
+            try:
+                pprint.pprint(kwargs)
+            except IOError, e:
+                if e.errno != errno.EPIPE:
+                    raise
+        else:
+            if sys.version_info < (2, 3):
+                from distutils.dist import DistributionMetadata
+                DistributionMetadata.classifiers = None
+                DistributionMetadata.download_url = None
+            try:
+                from setuptools import setup
+            except ImportError:
+                # package_data can't be handled this way ;-(
+                if self.package_data:
+                    print >>sys.stderr, (
+                        "can't import setuptools;"
+                        " some package data will not be properly installed")
+                from distutils.core import setup
+            setup(**kwargs)
+
+    def load_metadata(self, path):
+        f = open(path, "rU")
+        publication.load(f, metadata=self)
+        if self.platforms:
+            self.platforms = ", ".join(self.platforms)
+        m = re.match(r"\d+\.\d+(\.\d+)?(?:(?P<status>[ab])\d*)?$",
+                     self.version)
+        if m is not None:
+            devstatus = publication.STABLE
+            status = m.group("status")
+            if status == "a":
+                devstatus = publication.ALPHA
+            elif status == "b":
+                devstatus = publication.BETA
+            publication.set_development_status(self, devstatus)
+
+    def scan(self, name, directory, reldir):
+        init_py = os.path.join(directory, "__init__.py")
+        if os.path.isfile(init_py):
+            self.scan_package(name, directory, reldir)
+        else:
+            self.scan_collection(name, directory, reldir)
+
+    def scan_collection(self, name, directory, reldir):
+        # load the collection metadata
+        pkginfo = package.loadCollectionInfo(directory, reldir)
+        self.scan_basic(pkginfo)
+
+    def scan_package(self, name, directory, reldir):
+        # load the package metadata
+        pkginfo = package.loadPackageInfo(name, directory, reldir)
+        self.scan_basic(pkginfo)
+        self.ext_modules.extend(pkginfo.extensions)
+        self.add_package_dir(name, reldir)
+
+        # scan the files in the directory:
+        files = filter_names(os.listdir(directory))
+        for fn in files:
+            fnbase, ext = os.path.splitext(fn)
+            path = os.path.join(directory, fn)
+            if os.path.isdir(path):
+                init_py = os.path.join(path, "__init__.py")
+                if os.path.isfile(init_py):
+                    # if this package is published separately, skip it:
+                    # XXX we shouldn't actually need this if we only
+                    # use this class to scan in the generated
+                    # distributions
+                    if os.path.isfile(
+                        os.path.join(path, publication.PUBLICATION_CONF)):
+                        continue
+                    pkgname = "%s.%s" % (name, fn)
+                    self.scan_package(
+                        pkgname, path, posixpath.join(reldir, fn))
+                else:
+                    # an ordinary directory
+                    self.scan_directory(name, path, fn)
+            # Only add the file as package data if it's not a Python
+            # source file; Python files are copied in automatically.
+            elif not fn.endswith(".py"):
+                self.add_package_file(name, fn)
+
+        # We need to check that any files that were labelled as
+        # scripts or application data aren't copied in as package
+        # data; they shouldn't be installed into the package itself.
+        #
+        # XXX I'm not sure whether documentation files should be
+        # removed from package_data or not, given that there's no spec
+        # for installing documentation other than for RPMs.
+        #
+        relbase = posixpath.join(reldir, "")
+        pkgfiles = self.package_data.get(name, [])
+        non_pkgdata = pkginfo.script + pkginfo.header
+        for dir, files in pkginfo.data_files:
+            non_pkgdata.extend(files)
+        for ext in pkginfo.extensions:
+            for fn in ext.sources + getattr(ext, "depends", []):
+                if fn not in non_pkgdata:
+                    non_pkgdata.append(fn)
+        for fn in non_pkgdata:
+            pkgdatapath = fn[len(relbase):]
+            if pkgdatapath in pkgfiles:
+                pkgfiles.remove(pkgdatapath)
+
+    def scan_directory(self, pkgname, directory, reldir):
+        """Scan a data directory, adding files to package_data."""
+        files = filter_names(os.listdir(directory))
+        for fn in files:
+            path = os.path.join(directory, fn)
+            if os.path.isdir(path):
+                self.scan_directory(pkgname,
+                                    os.path.join(directory, fn),
+                                    posixpath.join(reldir, fn))
+            else:
+                self.add_package_file(pkgname, posixpath.join(reldir, fn))
+
+    def scan_basic(self, pkginfo):
+        self.scripts.extend(pkginfo.script)
+        if pkginfo.data_files:
+            if self.data_files:
+                # merge:
+                d = dict(self.data_files)
+                for dir, files in pkginfo.data_files:
+                    L = d.setdefault(dir, [])
+                    L.extend(files)
+                self.data_files = d.items()
+            else:
+                self.data_files = pkginfo.data_files
+
+    def add_package_dir(self, pkgname, reldir):
+        self.packages.append(pkgname)
+        if pkgname.replace(".", "/") != reldir:
+            self.package_dir[pkgname] = reldir
+
+    def add_package_file(self, pkgname, relfn):
+        L = self.package_data.setdefault(pkgname, [])
+        L.append(relfn)

Copied: zpkgtools/trunk/zpkgsetup/tests/input/package (from rev 25884, zpkgtools/trunk/zpkgtools/tests/input/package)

Copied: zpkgtools/trunk/zpkgsetup/tests/input/package2 (from rev 25884, zpkgtools/trunk/zpkgtools/tests/input/package2)

Added: zpkgtools/trunk/zpkgsetup/tests/runtests.py
===================================================================
--- zpkgtools/trunk/zpkgsetup/tests/runtests.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgsetup/tests/runtests.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,65 @@
+#! /usr/bin/env python
+##############################################################################
+#
+# Copyright (c) 2002, 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Script to run all the regression tests for zpkgtools."""
+
+import os
+import sys
+import unittest
+
+if __name__ == "__main__":
+    __file__ = sys.argv[0]
+
+TESTDIR = os.path.dirname(os.path.abspath(__file__))
+
+PKGDIR = os.path.dirname(TESTDIR) # the package directory
+TOPDIR = os.path.dirname(PKGDIR)
+
+
+def load_tests(name):
+    __import__(name)
+    mod = sys.modules[name]
+    return mod.test_suite()
+
+
+def make_directory_suite(pkgname, testdir):
+    L = []
+    for fn in os.listdir(testdir):
+        name, ext = os.path.splitext(fn)
+        if name[:4] == "test" and ext == ".py":
+            L.append(load_tests("%s.%s" % (pkgname, name)))
+    suite = L.pop()
+    for t in L:
+        suite.addTest(t)
+    return suite
+
+
+def test_suite():
+    return make_directory_suite("zpkgsetup.tests", TESTDIR)
+
+
+class MyTestProgram(unittest.TestProgram):
+    """Test runner program that doesn't use docstrings as descriptions."""
+
+    def runTests(self):
+        if self.testRunner is None:
+            self.testRunner = unittest.TextTestRunner(descriptions=False,
+                                                      verbosity=self.verbosity)
+        unittest.TestProgram.runTests(self)
+
+
+if __name__ == "__main__":
+    if TOPDIR not in sys.path:
+        sys.path.insert(0, TOPDIR)
+    MyTestProgram(defaultTest="test_suite")


Property changes on: zpkgtools/trunk/zpkgsetup/tests/runtests.py
___________________________________________________________________
Name: svn:mime-type
   + text/x-python
Name: svn:eol-style
   + native

Copied: zpkgtools/trunk/zpkgsetup/tests/test_cfgparser.py (from rev 25884, zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py	2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/tests/test_cfgparser.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,162 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for zpkgtools.cfgparser."""
+
+import unittest
+
+from StringIO import StringIO
+
+from zpkgsetup import cfgparser
+
+
+class SimpleSection:
+
+    finished = False
+    ending_parent = None
+    ending_typename = None
+    ending_name = None
+
+    def __init__(self, parent=None, typename=None, name=None):
+        self.parent = parent
+        self.typename = typename
+        self.name = name
+
+
+class AnythingGoesSchema:
+
+    def getConfiguration(self):
+        return SimpleSection()
+
+    def startSection(self, parent, typename, name):
+        return SimpleSection(parent, typename, name)
+
+    def finishSection(self, section):
+        section.finished = True
+        return section
+
+    def endSection(self, parent, typename, name, child):
+        child.ending_parent = parent
+        child.ending_typename = typename
+        child.ending_name = name
+        if not hasattr(parent, typename):
+            setattr(parent, typename, [])
+        getattr(parent, typename).append(child)
+        self.finishSection(child)
+
+    def addValue(self, section, key, value):
+        key = key.lower().replace("-", "_")
+        if not hasattr(section, key):
+            setattr(section, key, [])
+        getattr(section, key).append(value)
+
+
+class ParserTestCase(unittest.TestCase):
+
+    schema = AnythingGoesSchema()
+
+    def createParser(self, text=""):
+        sio = StringIO(text)
+        self.parser = cfgparser.Parser(sio, "<some-url>", self.schema)
+        return self.parser
+
+    def test_replace(self):
+        # "legal" values are those that are legal in ZConfig
+        eq = self.assertEqual
+        raises = self.assertRaises
+        replace = self.createParser().replace
+
+        # some legal values that don't have '$':
+        eq(replace(""), "")
+        eq(replace(" foo bar "), " foo bar ")
+        eq(replace("x"), "x")
+
+        # legal, supported values with '$':
+        eq(replace("$$"), "$")
+        eq(replace("$$$$"), "$$")
+        eq(replace("$$xyz$$"), "$xyz$")
+
+        # legal, unsupported values (all have '$'):
+        raises(cfgparser.ConfigurationError, replace, "$foo")
+        raises(cfgparser.ConfigurationError, replace, "${foo-bar}")
+
+        # illegal values:
+        raises(cfgparser.ConfigurationError, replace, "$")
+        raises(cfgparser.ConfigurationError, replace, "foo$")
+
+    def test_schema_use(self):
+        eq = self.assertEqual
+        p = self.createParser("""
+            # This is a comment.
+
+            key value 1
+            key value 2
+            <section/>
+            <section foo/>
+            <section>
+              key  value 3
+            </section>
+            <section splat>
+              <inner>
+                key value 5
+              </inner>
+              key value 4
+            </section>
+            """)
+        cf = p.load()
+        self.check_section(cf, None, None, None, key=["value 1", "value 2"])
+        s1, s2, s3, s4 = cf.section
+        self.check_section(s1, cf, None, "section")
+        self.check_section(s2, cf, "foo", "section")
+        self.check_section(s3, cf, None, "section", key=["value 3"])
+        self.check_section(s4, cf, "splat", "section", key=["value 4"])
+        inner, = s4.inner
+        self.check_section(inner, s4, None, "inner", key=["value 5"])
+
+    def check_section(self, section, parent, name, typename, **attrs):
+        self.assert_(section.finished)
+        self.assert_(section.parent is parent)
+        self.assert_(section.parent is section.ending_parent)
+        self.assertEqual(section.name, name)
+        self.assertEqual(section.name, section.ending_name)
+        self.assertEqual(section.typename, typename)
+        self.assertEqual(section.typename, section.ending_typename)
+        for name, value in attrs.iteritems():
+            v = getattr(section, name)
+            self.assertEqual(v, value)
+
+
+class SchemaTestCase(unittest.TestCase):
+
+    top_level_converted = False
+
+    def setUp(self):
+        self.schema = cfgparser.Schema(
+            ({}, [], self.top_level_conversion))
+
+    def top_level_conversion(self, section):
+        self.top_level_converted = True
+        return section
+
+    def test_getConfiguration(self):
+        cf = self.schema.getConfiguration()
+        self.failIf(self.top_level_converted)
+
+
+def test_suite():
+    suite = unittest.makeSuite(ParserTestCase)
+    suite.addTest(unittest.makeSuite(SchemaTestCase))
+    return suite
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="test_suite")

Copied: zpkgtools/trunk/zpkgsetup/tests/test_package.py (from rev 25884, zpkgtools/trunk/zpkgtools/tests/test_package.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_package.py	2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/tests/test_package.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,213 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for zpkgtools.package."""
+
+import doctest
+import os.path
+import shutil
+import tempfile
+import unittest
+
+from distutils.core import Extension
+from StringIO import StringIO
+
+from zpkgsetup import cfgparser
+from zpkgsetup import package
+
+
+class PackageInfoTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.tmpdir = tempfile.mkdtemp(prefix="test_package_")
+
+    def tearDown(self):
+        shutil.rmtree(self.tmpdir)
+
+    def write_config(self, text):
+        self.write_file(package.PACKAGE_CONF, text)
+
+    def write_file(self, name, text):
+        f = open(os.path.join(self.tmpdir, name), "w")
+        f.write(text)
+        f.close()
+
+    def test_empty_pkginfo(self):
+        self.write_config("# empty configuration file\n")
+        pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
+        eq = self.assertEqual
+        eq(pkginfo.extensions, [])
+        eq(pkginfo.documentation, [])
+        eq(pkginfo.script, [])
+
+    def test_missing_pkginfo(self):
+        pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
+        eq = self.assertEqual
+        eq(pkginfo.extensions, [])
+        eq(pkginfo.documentation, [])
+        eq(pkginfo.script, [])
+
+    def test_nonempty_pkginfo(self):
+        self.write_config("documentation  doc/README.txt\n"
+                          "script         bin/runme.py\n"
+                          "<extension cricket>\n"
+                          "  source     jiminy.c\n"
+                          "  define     FOO\n"
+                          "  define     BAR = splat\n"
+                          "  undefine   CRUNCHY NUGGET\n"
+                          "  depends-on cricket.h\n"
+                          "  depends-on innerds.c\n"
+                          "  language   C\n"
+                          "</extension>\n")
+        os.mkdir(os.path.join(self.tmpdir, "doc"))
+        self.write_file(os.path.join("doc", "README.txt"),
+                        "docs go here")
+        os.mkdir(os.path.join(self.tmpdir, "bin"))
+        self.write_file(os.path.join("bin", "runme.py"),
+                        "#!/bin/sh\nexit\n")
+        pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
+        eq = self.assertEqual
+        eq(len(pkginfo.extensions), 1)
+        eq(pkginfo.documentation, ["bar/doc/README.txt"])
+        eq(pkginfo.script, ["bar/bin/runme.py"])
+
+        ext = pkginfo.extensions[0]
+        self.assert_(isinstance(ext, Extension))
+        eq(ext.name, "foo.cricket")
+        eq(ext.sources, ["bar/jiminy.c"])
+        eq(ext.depends, ["bar/cricket.h", "bar/innerds.c"])
+        eq(ext.define_macros, [("FOO", None), ("BAR", "splat")])
+        eq(ext.undef_macros, ["CRUNCHY", "NUGGET"])
+        eq(ext.language, "C")
+
+    def test_broken_extension_too_many_languages(self):
+        self.write_config("<extension cricket>\n"
+                          "  source     jiminy.c\n"
+                          "  language   C\n"
+                          "  language   C++\n"
+                          "</extension>\n")
+        self.assertRaises(cfgparser.ConfigurationError,
+                          package.loadPackageInfo, "foo", self.tmpdir, "bar")
+
+    def test_broken_extension_without_name(self):
+        self.write_config("<extension>\n"
+                          "  source  jiminy.c\n"
+                          "</extension>\n")
+        self.assertRaises(cfgparser.ConfigurationError,
+                          package.loadPackageInfo, "foo", self.tmpdir, "bar")
+
+    def test_broken_extension_no_source(self):
+        self.write_config("<extension cricket/>")
+        self.assertRaises(cfgparser.ConfigurationError,
+                          package.loadPackageInfo, "foo", self.tmpdir, "bar")
+
+    def test_collection_empty_pkginfo(self):
+        self.write_config("# empty configuration file\n")
+        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+        eq = self.assertEqual
+        eq(pkginfo.extensions, [])
+        eq(pkginfo.documentation, [])
+        eq(pkginfo.script, [])
+
+    def test_collection_missing_pkginfo(self):
+        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+        eq = self.assertEqual
+        eq(pkginfo.extensions, [])
+        eq(pkginfo.documentation, [])
+        eq(pkginfo.script, [])
+
+    def test_collection_pkginfo(self):
+        self.write_config("documentation  doc/*\n"
+                          "script         bin/*.py\n")
+        os.mkdir(os.path.join(self.tmpdir, "doc"))
+        self.write_file(os.path.join("doc", "README.txt"),
+                        "docs go here")
+        os.mkdir(os.path.join(self.tmpdir, "bin"))
+        self.write_file(os.path.join("bin", "runme.py"),
+                        "#!/bin/sh\nexit\n")
+        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+        eq = self.assertEqual
+        eq(len(pkginfo.extensions), 0)
+        eq(pkginfo.documentation, ["doc/README.txt"])
+        eq(pkginfo.script, ["bin/runme.py"])
+
+    def test_collection_pkginfo_disallows_extensions(self):
+        self.write_config("<extension foo>\n"
+                          "  source  foo.c\n"
+                          "</extension>\n")
+        self.assertRaises(ValueError, package.loadCollectionInfo,
+                          self.tmpdir, None)
+
+    def test_data_files_1(self):
+        self.write_config("<data-files etc>\n"
+                          "  foo*\n"
+                          "</data-files>\n")
+        self.write_file("foo1.conf", "config goes here")
+        self.write_file("foo2.conf", "config goes here")
+        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+        pkginfo.data_files[0][1].sort()
+        self.assertEqual(pkginfo.data_files,
+                         [("etc", ["foo1.conf", "foo2.conf"])])
+
+    def test_data_files_2(self):
+        self.write_config("<data-files var>\n"
+                          "  foo2.conf\n"
+                          "</data-files>\n"
+                          "<data-files etc>\n"
+                          "  foo1.conf\n"
+                          "</data-files>\n")
+        self.write_file("foo1.conf", "config goes here")
+        self.write_file("foo2.conf", "config goes here")
+        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
+        pkginfo.data_files.sort()
+        self.assertEqual(pkginfo.data_files,
+                         [("etc", ["foo1.conf"]),
+                           ("var", ["foo2.conf"])])
+
+    def test_data_files_error_has_value(self):
+        self.write_config("<data-files etc>\n"
+                          "  foo bar\n"
+                          "</data-files>\n")
+        self.assertRaises(cfgparser.ConfigurationError,
+                          package.loadCollectionInfo, self.tmpdir, None)
+
+    def test_data_files_error_has_nested_section(self):
+        self.write_config("<data-files etc>\n"
+                          "  <extension foo>\n"
+                          "  </extension>\n"
+                          "</data-files>\n")
+        self.assertRaises(cfgparser.ConfigurationError,
+                          package.loadCollectionInfo, self.tmpdir, None)
+
+    def test_data_files_error_section_without_name(self):
+        self.write_config("<data-files>\n"
+                          "</data-files>\n")
+        self.assertRaises(cfgparser.ConfigurationError,
+                          package.loadCollectionInfo, self.tmpdir, None)
+
+    def test_data_files_error_sections_with_same_name(self):
+        self.write_config("<data-files etc>\n"
+                          "</data-files>\n"
+                          "<data-files etc/>\n"
+                          "</data-files>\n")
+        self.assertRaises(cfgparser.ConfigurationError,
+                          package.loadCollectionInfo, self.tmpdir, None)
+
+
+def test_suite():
+    suite = doctest.DocTestSuite("zpkgsetup.package")
+    suite.addTest(unittest.makeSuite(PackageInfoTestCase))
+    return suite
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="test_suite")

Copied: zpkgtools/trunk/zpkgsetup/tests/test_publication.py (from rev 25884, zpkgtools/trunk/zpkgtools/tests/test_publication.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_publication.py	2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/tests/test_publication.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,59 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests for zpkgtools.publication
+
+$Id: test_publication.py,v 1.1 2004/06/14 20:46:41 fdrake Exp $
+"""
+import unittest
+
+from zpkgsetup import publication
+
+
+class DevelopmentStatusTestCase(unittest.TestCase):
+
+    def test_set_development_status_replace_1(self):
+        metadata = publication.loads(
+            "Name: foo\n"
+            "Classifier: Development Status:: 3 - Alpha\n")
+        publication.set_development_status(metadata, publication.BETA)
+        self.assertEqual(metadata.classifiers, [publication.BETA])
+
+    def test_set_development_status_replace_2(self):
+        metadata = publication.loads(
+            "Name: foo\n"
+            "Classifier: Environment :: Console\n"
+            "Classifier: Development Status:: 3 - Alpha\n"
+            "Classifier: Intended Audience :: Developers\n")
+        publication.set_development_status(metadata, publication.BETA)
+        self.assertEqual(metadata.classifiers, [
+            "Environment :: Console",
+            publication.BETA,
+            "Intended Audience :: Developers",
+            ])
+
+    def test_set_development_status_append(self):
+        metadata = publication.loads(
+            "Name: foo\n"
+            "Classifier: Environment :: Console\n"
+            "Classifier: Intended Audience :: Developers\n")
+        publication.set_development_status(metadata, publication.BETA)
+        self.assertEqual(metadata.classifiers, [
+            "Environment :: Console",
+            "Intended Audience :: Developers",
+            publication.BETA,
+            ])
+
+
+def test_suite():
+    return unittest.makeSuite(DevelopmentStatusTestCase)

Copied: zpkgtools/trunk/zpkgsetup/tests/test_setup.py (from rev 25884, zpkgtools/trunk/zpkgtools/tests/test_setup.py)
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_setup.py	2004-06-16 18:26:51 UTC (rev 25884)
+++ zpkgtools/trunk/zpkgsetup/tests/test_setup.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1,57 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Tests of zpkgtools.setup."""
+
+import os
+import unittest
+
+from zpkgsetup import publication
+from zpkgsetup import setup
+
+
+here = os.path.dirname(os.path.abspath(__file__))
+
+
+class SetupContextTestCase(unittest.TestCase):
+
+    def test_python_files_as_data(self):
+        packagedir = os.path.join(here, "input", "package")
+        publicationcfg = os.path.join(packagedir, publication.PUBLICATION_CONF)
+        setupfile = os.path.join(here, "input", "setup.py")
+        f = open(publicationcfg, "w")
+        f.write("Metadata-version: 1.0\n"
+                "Name: foo\n")
+        f.close()
+        try:
+            context = setup.SetupContext("package", "0.1.234", setupfile)
+            context.initialize()
+            context.package_data["package"].sort()
+            self.assertEqual(context.package_data,
+                             {"package": ["PUBLICATION.cfg",
+                                          "datadir/justdata.py"]})
+        finally:
+            os.unlink(publicationcfg)
+
+    def test_extension_sources_are_not_package_data(self):
+        packagedir = os.path.join(here, "input", "package2")
+        setupfile = os.path.join(here, "input", "setup.py")
+        context = setup.SetupContext("package2", "0.1.234", setupfile)
+        context.initialize()
+        context.package_data["package2"].sort()
+        self.assertEqual(context.package_data,
+                         {"package2": ["PUBLICATION.cfg", "SETUP.cfg"]})
+
+
+def test_suite():
+    return unittest.makeSuite(SetupContextTestCase)

Added: zpkgtools/trunk/zpkgtools/DEPENDENCIES.cfg
===================================================================
--- zpkgtools/trunk/zpkgtools/DEPENDENCIES.cfg	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/DEPENDENCIES.cfg	2004-06-17 16:12:11 UTC (rev 25887)
@@ -0,0 +1 @@
+zpkgsetup

Modified: zpkgtools/trunk/zpkgtools/__init__.py
===================================================================
--- zpkgtools/trunk/zpkgtools/__init__.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/__init__.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -23,9 +23,10 @@
 .. __: http://www.zope.org/Resources/ZPL
 
 """
+import zpkgsetup
 
 
-class Error(Exception):
+class Error(zpkgsetup.Error):
     """Base class for exceptions raised by zpkgtools."""
 
 

Modified: zpkgtools/trunk/zpkgtools/app.py
===================================================================
--- zpkgtools/trunk/zpkgtools/app.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/app.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -23,13 +23,14 @@
 
 import zpkgtools
 
+from zpkgsetup import loggingapi as logging
+from zpkgsetup import package
+from zpkgsetup import publication
+
 from zpkgtools import config
 from zpkgtools import dependencies
 from zpkgtools import include
 from zpkgtools import loader
-from zpkgtools import loggingapi as logging
-from zpkgtools import package
-from zpkgtools import publication
 from zpkgtools import runlog
 
 
@@ -199,7 +200,7 @@
         """Include any support code needed by the generated setup.py
         files.
 
-        This will add the ``setuptools`` and ``zpkgtools`` packages to
+        This will add the ``setuptools`` and ``zpkgsetup`` packages to
         the output directory if not already present, but they won't be
         added to the set of packages that will be installed by the
         resulting distribution.
@@ -210,8 +211,8 @@
             self.loader = loader.Loader()
         os.mkdir(os.path.join(self.destination, "Support"))
         self.include_support_package(
-            "zpkgtools", ("cvs://cvs.zope.org/cvs-repository"
-                          ":Packages/zpkgtools/zpkgtools"))
+            "zpkgsetup", ("svn://svn.zope.org/repos/main/zpkgtools/tags/*/"
+                          "zpkgsetup"))
         self.include_support_package(
             "setuptools", ("cvs://cvs.python.sourceforge.net/cvsroot/python"
                            ":python/nondist/sandbox/setuptools/setuptools"))
@@ -443,7 +444,7 @@
         self.ip.add_output(setup_py)
         f = open(setup_py, "w")
         print >>f, SETUP_HEADER
-        print >>f, "context = zpkgtools.setup.SetupContext("
+        print >>f, "context = zpkgsetup.setup.SetupContext("
         print >>f, "    %r, %r, __file__)" % (self.name, version)
         print >>f
         print >>f, "context.initialize()"
@@ -472,7 +473,7 @@
 if os.path.isdir(support_dir):
     sys.path.insert(0, support_dir)
 
-import zpkgtools.setup
+import zpkgsetup.setup
 
 """
 

Deleted: zpkgtools/trunk/zpkgtools/cfgparser.py
===================================================================
--- zpkgtools/trunk/zpkgtools/cfgparser.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/cfgparser.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,360 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Extra-lite parser for a `ZConfig`_-like configuration syntax.
-
-There is no support for external schemas; schemas are simpler and must
-be specified using Python data structures.
-
-There is no support for any %-directives, but dollar signs in values
-must be doubled to ensure compatibility with `ZConfig`_.
-
-.. _ZConfig:  http://www.zope.org/Members/fdrake/zconfig/
-
-"""
-
-import re
-
-
-class ConfigurationError(Exception):
-    """Exception raised for errors in a configuration file.
-
-    :ivar url: URL of the resource being read when the error was
-      detected.
-
-    :ivar lineno: Line number within the resource at which the
-      error was detected.
-
-    """
-
-    def __init__(self, message, url=None, lineno=None):
-        """Initialize the ConfigurationError instance.
-
-        :param message: Text of the error message.
-
-        :param url: URL of the resource being read when the error was
-          detected.
-
-        :param lineno: Line number within the resource at which the
-          error was detected.
-
-        """
-        Exception.__init__(self, message)
-        self.url = url
-        self.lineno = lineno
-
-    def __str__(self):
-        s = Exception.__str__(self)
-        if self.url:
-            s = "%s\n(%s" % (s, self.url)
-            if self.lineno is not None:
-                s = "%s, line %s" % (s, self.lineno)
-            s += ")"
-        return s
-
-
-class Schema:
-    """Schema definition that can be used by the Parser class to
-    construct a configuration.
-
-    The definition is defined as a set of *type definitions*.  Each
-    type definition is a triple containing a dictionary, a list, and a
-    function (or `None`).  The dictionary maps the names of the keys
-    allowed in the section to conversion functions for the values (or
-    None if no conversion is required).  The list names the section
-    types which can occur in the section.  The function is used to
-    convert a `SectionValue` representing the collected values to the
-    actual value of the section itself; if `None` is used, no
-    conversion is performed.
-
-    """
-
-    def __init__(self, toplevel, typedefs=None):
-        """Initialize a schema definition based on type definitions.
-
-        :param toplevel: Type definition that represents the otherwise
-          anonymous top-level section of a configuration.
-
-        :param typedefs: Mapping from typenames (which must be given
-          as lower-case strings) to type definitions.  Only section
-          types specified in `typedefs` can be used anywhere in
-          configurations described by the schema.
-
-        """
-        self._toplevel = toplevel
-        if typedefs is None:
-            typedefs = {}
-        self._typedefs = typedefs
-
-    def getConfiguration(self):
-        """Return a configuration object for the top-level section.
-
-        :return: New configuration object.
-
-        The attributes of the configuration object represent values
-        that have not been specified in a configuration file; these
-        will be filled in during parsing.
-        """
-        return self.createSection(None, None, self._toplevel)
-
-    def startSection(self, parent, typename, name):
-        # make sure typename is defined:
-        typedef = self._typedefs.get(typename)
-        if typedef is None:
-            raise ConfigurationError("unknown section type: %s" % typename)
-        # make sure typename is allowed:
-        x, sects, x = parent.getSectionDefinition()
-        if typename not in sects:
-            parent_type = parent.getSectionType()
-            if parent_type:
-                msg = ("%r sections not allowed in %r sections"
-                       % (typename, parent_type))
-            else:
-                msg = "%r sections not allowed" % typename
-            raise ConfigurationError(msg)
-        return self.createSection(name, typename, typedef)
-
-    def createSection(self, name, typename, typedef):
-        child = SectionValue(name, typename, typedef)
-        keys, sects, x = typedef
-        # initialize the defaults:
-        for name in keys:
-            name = name.lower().replace("-", "_")
-            setattr(child, name, [])
-        for name in sects:
-            name = name.lower().replace("-", "_")
-            setattr(child, name, [])
-        return child
-
-    def finishSection(self, section):
-        x, x, datatype = section.getSectionDefinition()
-        if datatype is not None:
-            typename = section.getSectionType()
-            try:
-                section = datatype(section)
-            except ValueError, e:
-                raise ConfigurationError(
-                    "could not convert %r section value: %s"
-                    % (typename, e))
-        return section
-
-    def endSection(self, parent, typename, name, child):
-        value = self.finishSection(child)
-        getattr(parent, typename).append(value)
-
-    def addValue(self, section, key, value):
-        keys, x, x = section.getSectionDefinition()
-        keyname = key.lower()
-        if keyname not in keys:
-            typename = section.getSectionType()
-            if typename:
-                msg = "key %r not defined in %r sections" % (key, typename)
-            else:
-                msg = "key %r not defined" % key
-            raise ConfigurationError(msg)
-        datatype = keys[keyname]
-        if datatype is not None:
-            try:
-                value = datatype(value)
-            except ValueError, e:
-                raise ConfigurationError("could not convert value: %s" % e)
-        attrname = keyname.replace("-", "_")
-        getattr(section, attrname).append(value)
-
-
-# These regular expressions should match the corresponding definitions
-# in ZConfig.cfgparser since this needs to be a format that could be
-# read by ZConfig with an appropriate schema definition.
-#
-_name_re = r"[^\s()]+"
-_keyvalue_rx = re.compile(r"(?P<key>%s)\s*(?P<value>[^\s].*)?$"
-                          % _name_re)
-_section_start_rx = re.compile(r"(?P<type>%s)"
-                               r"(?:\s+(?P<name>%s))?"
-                               r"$"
-                               % (_name_re, _name_re))
-
-_nulljoin = "".join
-
-
-class Parser:
-    """Parser for ZConfig-like configuration files."""
-
-    def __init__(self, file, url, schema):
-        self.schema = schema
-        self.file = file
-        self.url = url
-        self.lineno = 0
-        self.stack = []   # [(type, name, prevmatcher), ...]
-
-    def nextline(self):
-        line = self.file.readline()
-        if line:
-            self.lineno += 1
-            return False, line.strip()
-        else:
-            return True, None
-
-    def load(self):
-        section = self.schema.getConfiguration()
-        self.parse(section)
-        try:
-            return self.schema.finishSection(section)
-        except ConfigurationError, e:
-            e.lineno = self.lineno
-            e.url = self.url
-            raise
-
-    def parse(self, section):
-        done, line = self.nextline()
-        while not done:
-            if line[:1] in ("", "#"):
-                # blank line or comment
-                pass
-
-            elif line[:2] == "</":
-                # section end
-                if line[-1] != ">":
-                    self.error("malformed section end")
-                section = self.end_section(section, line[2:-1])
-
-            elif line[0] == "<":
-                # section start
-                if line[-1] != ">":
-                    self.error("malformed section start")
-                section = self.start_section(section, line[1:-1])
-
-            elif line[0] == "%":
-                self.error("ZConfig-style directives are not supported")
-
-            else:
-                self.handle_key_value(section, line)
-
-            done, line = self.nextline()
-
-        if self.stack:
-            self.error("unclosed sections not allowed")
-
-    def start_section(self, section, rest):
-        isempty = rest[-1:] == "/"
-        if isempty:
-            text = rest[:-1].rstrip()
-        else:
-            text = rest.rstrip()
-        # parse section start stuff here
-        m = _section_start_rx.match(text)
-        if not m:
-            self.error("malformed section header")
-        type, name = m.group('type', 'name')
-        type = type.lower()
-        #
-        # XXX Argh!  Converting section names to lower-case was a
-        # mistake in ZConfig, but we have to honor case here for
-        # <extension> sections.  We need to add some way to control
-        # the "nametype" of sections in ZConfig anyway.
-        #
-        # if name:
-        #    name = name.lower()
-        #
-        try:
-            newsect = self.schema.startSection(section, type, name)
-        except ConfigurationError, e:
-            e.lineno = self.lineno
-            e.url = self.url
-            raise
-        if isempty:
-            try:
-                self.schema.endSection(section, type, name, newsect)
-            except ConfigurationError, e:
-                e.lineno = self.lineno
-                e.url = self.url
-                raise
-            return section
-        else:
-            self.stack.append((type, name, section))
-            return newsect
-
-    def end_section(self, section, rest):
-        if not self.stack:
-            self.error("unexpected section end")
-        type = rest.rstrip().lower()
-        opentype, name, prevsection = self.stack.pop()
-        if type != opentype:
-            self.error("unbalanced section end")
-        try:
-            self.schema.endSection(prevsection, type, name, section)
-        except ConfigurationError, e:
-            e.lineno = self.lineno
-            e.url = self.url
-            raise
-        return prevsection
-
-    def handle_key_value(self, section, rest):
-        m = _keyvalue_rx.match(rest)
-        if not m:
-            self.error("malformed configuration data")
-        key, value = m.group('key', 'value')
-        if value:
-            value = self.replace(value)
-        else:
-            value = ''
-        try:
-            self.schema.addValue(section, key, value)
-        except ConfigurationError, e:
-            e.lineno = self.lineno
-            e.url = self.url
-            raise
-
-    def replace(self, text):
-        parts = []
-        rest = text
-        while "$" in rest:
-            i = rest.index("$")
-            if i:
-                parts.append(rest[:i])
-            rest = rest[i+1:]
-            if not rest:
-                self.error("text cannot end with a bare '$'")
-            if rest[0] == "$":
-                parts.append("$")
-                rest = rest[1:]
-            else:
-                self.error("unsupported substitution syntax")
-        parts.append(rest)
-        return _nulljoin(parts)
-
-    def error(self, message):
-        raise ConfigurationError(message, self.url, self.lineno)
-
-
-class SectionValue:
-    """Generic bag-of-values object for a section."""
-
-    def __init__(self, name, typename, typedef):
-        self._name = name
-        self._typename = typename
-        self._typedef = typedef
-
-    def getSectionName(self):
-        """Return the name of the section, or `None`."""
-        return self._name
-
-    def getSectionType(self):
-        """Return the name of the section type."""
-        return self._typename
-
-    def getSectionDefinition(self):
-        """Return the data structure that represents the type of this
-        section value.
-        """
-        return self._typedef

Modified: zpkgtools/trunk/zpkgtools/config.py
===================================================================
--- zpkgtools/trunk/zpkgtools/config.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/config.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -26,7 +26,7 @@
 import os
 import urllib
 
-from zpkgtools import cfgparser
+from zpkgsetup import cfgparser
 from zpkgtools import locationmap
 
 

Modified: zpkgtools/trunk/zpkgtools/include.py
===================================================================
--- zpkgtools/trunk/zpkgtools/include.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/include.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -14,41 +14,28 @@
 """Processor for inclusions when building a release.
 
 :Variables:
-  - `EXCLUDE_NAMES`: Names of files and directories that will be
-    excluded from copying.  These are generally related to source
-    management systems, but don't need to be.
-
-  - `EXCLUDE_PATTERNS`: Glob patterns used to filter the set of files
-    that are copied.  Any file with a name matching these patterns
-    will be ignored.
-
   - `PACKAGE_CONF`: The name of the file that specifies how the
     package is assembled.
 
 """
 
-import fnmatch
 import glob
 import os
 import posixpath
 import shutil
 import urllib
 
-from zpkgtools import Error
+from zpkgsetup import cfgparser
+from zpkgsetup import loggingapi as logging
+from zpkgsetup import publication
+from zpkgsetup import setup
 
-from zpkgtools import cfgparser
+from zpkgtools import Error
 from zpkgtools import loader
-from zpkgtools import loggingapi as logging
-from zpkgtools import publication
 
 
 logger = logging.getLogger(__name__)
 
-
-# Names that are exluded from globbing results:
-EXCLUDE_NAMES = ["CVS", ".cvsignore", "RCS", "SCCS", ".svn"]
-EXCLUDE_PATTERNS = ["*.py[cdo]", "*.s[ol]", ".#*", "*~"]
-
 # Name of the configuration file:
 PACKAGE_CONF = "PACKAGE.cfg"
 
@@ -102,19 +89,6 @@
     return config
 
 
-def filter_names(names):
-    """Given a list of file names, return those names that should be copied.
-    """
-    names = [n for n in names
-             if n not in EXCLUDE_NAMES]
-    # This is needed when building a distro from a working
-    # copy (likely a checkout) rather than a pristine export:
-    for pattern in EXCLUDE_PATTERNS:
-        names = [n for n in names
-                 if not fnmatch.fnmatch(n, pattern)]
-    return names
-
-
 def normalize_path(path, type, group):
     if ":" in path:
         scheme, rest = urllib.splittype(path)
@@ -284,7 +258,7 @@
         prefix = os.path.join(source, "")
         for pat in patterns:
             path = os.path.join(source, pat)
-            expansions = filter_names(glob.glob(path))
+            expansions = setup.filter_names(glob.glob(path))
             if not expansions:
                 raise InclusionSpecificationError(
                     "%r doesn't match any files in <%s>" % (pat, self.group),
@@ -295,7 +269,7 @@
         excludes = []
         for pat in self.excludes:
             path = os.path.join(source, pat)
-            expansions = filter_names(glob.glob(path))
+            expansions = setup.filter_names(glob.glob(path))
             if not expansions:
                 raise InclusionSpecificationError(
                     "%r doesn't match any files in <%s>" % (pat, self.group),
@@ -374,8 +348,8 @@
         # to modify the list of directories which are considered.
         #
         for dirname, dirs, files in os.walk(source, topdown=True):
-            dirs[:] = filter_names(dirs)
-            files = filter_names(files)
+            dirs[:] = setup.filter_names(dirs)
+            files = setup.filter_names(files)
 
             # reldir is the name of the directory to write to,
             # relative to destination.  It will be '' at the top

Modified: zpkgtools/trunk/zpkgtools/loader.py
===================================================================
--- zpkgtools/trunk/zpkgtools/loader.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/loader.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -26,8 +26,9 @@
 import urllib2
 import urlparse
 
+from zpkgsetup import loggingapi as logging
+
 from zpkgtools import cvsloader
-from zpkgtools import loggingapi as logging
 from zpkgtools import svnloader
 
 

Modified: zpkgtools/trunk/zpkgtools/locationmap.py
===================================================================
--- zpkgtools/trunk/zpkgtools/locationmap.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/locationmap.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -22,9 +22,10 @@
 import urlparse
 import UserDict
 
+from zpkgsetup import loggingapi as logging
+
 from zpkgtools import cvsloader
 from zpkgtools import loader
-from zpkgtools import loggingapi as logging
 from zpkgtools import svnloader
 
 

Deleted: zpkgtools/trunk/zpkgtools/loggingapi.py
===================================================================
--- zpkgtools/trunk/zpkgtools/loggingapi.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/loggingapi.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,92 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Compatibility wrapper around the logging package.
-
-If the logging package isn't available (as in Python 2.2), this
-provides a limited implementation so the zpkgtools setup.py support
-code doesn't fall over.
-
-This isn't sufficient to support building packages with Python 2.2.
-
-$Id: loggingapi.py,v 1.1 2004/06/11 19:24:35 fdrake Exp $
-"""
-
-try:
-    from logging import getLogger
-    from logging import CRITICAL, FATAL, ERROR, WARNING, WARN
-    from logging import INFO, DEBUG, NOTSET
-    from logging import StreamHandler
-
-except ImportError:
-
-    CRITICAL = 50
-    FATAL = CRITICAL
-    ERROR = 40
-    WARNING = 30
-    WARN = WARNING
-    INFO = 20
-    DEBUG = 10
-    NOTSET = 0
-
-
-    _loggers = {}
-
-    def getLogger(name=None):
-        if "root" not in _loggers:
-            _loggers["root"] = Logger("root")
-            _loggers["root"].setLevel(WARNING)
-        name = name or "root"
-        if name not in _loggers:
-            _loggers[name] = Logger(name, _loggers["root"])
-        return _loggers[name]
-
-
-    class Logger:
-
-        def __init__(self, name, root=None):
-            self.name = name
-            self.level = NOTSET
-            self._handler = None
-            self._root = root
-
-        def setLevel(self, level):
-            self.level = level
-
-        def addHandler(self, handler):
-            self._handler = handler
-
-        def log(self, level, msg, *args, **kwargs):
-            loggers = [self]
-            if self._root is not None:
-                loggers.append(self._root)
-
-            for logger in loggers:
-                effective_level = logger.level
-                if effective_level == NOTSET and logger._root is not None:
-                    effective_level = self._root.level
-                if level >= effective_level:
-                    self._log(self.name, level, msg, args, kwargs)
-
-        def _log(self, name, level, msg, args, kwargs):
-            if args:
-                msg = msg % args
-            elif kwargs:
-                msg = msg % kwargs
-            msg = "%s(%s):%s" % (name, level, msg)
-            print >>self._handler, msg
-
-
-    def StreamHandler():
-        import sys
-        return sys.stderr

Deleted: zpkgtools/trunk/zpkgtools/package.py
===================================================================
--- zpkgtools/trunk/zpkgtools/package.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/package.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,518 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Support for handling package configuration files.
-
-The package configuration files handled by this module provide
-information about the software and documentation contents of a
-distribution component.  The same kinds of information can be
-described for any component, with the exception that extensions only
-make sense for package components.
-
-Package configuration files use a syntax very like the `ZConfig`_
-package, but fewer features are available.  The specific syntax is
-implemented by the `cfgparser` module.
-
-.. _ZConfig:  http://www.zope.org/Members/fdrake/zconfig/
-
-There are only a few types of information which can appear in a
-package configuration file; the file is intended to describe what a
-package provides that is not a module or data file.  The three types
-of things which can be listed in the file are:
-
-- scripts
-- documentation
-- extensions
-
-The scripts and documentation files are listed very simply::
-
-  documentation  *.txt
-  documentation  apiref.pdf
-
-  script  scritps/*
-
-The value to the right of the identifying keyword is a portable glob
-pattern, where *portable* here means the pattern uses the POSIX
-notation.  Path components should be separated by forward slashes
-(like all paths used with distutils), ``?`` can be replaced by any
-single character, and ``*`` can be replaced by zero or more
-characters.
-
-
-:Variables:
-  - `PACKAGE_CONF`:  Name of the package information file.
-
-:Groups:
-  - `Public interface`: loadCollectionInfo loadPackageInfo
-  - `Helper functions`: create_extension expand_globs read_package_info
-  - `Datatype functions`: cpp_definition cpp_names path_ref extension
-
-"""
-
-import glob
-import os
-import posixpath
-import re
-import urllib
-
-from distutils.core import Extension
-from StringIO import StringIO
-
-from zpkgtools import cfgparser
-
-
-PACKAGE_CONF = "SETUP.cfg"
-
-
-def loadPackageInfo(pkgname, directory, reldir):
-    """Load package information for a Python package.
-
-    :return: Package information object.
-
-    :Parameters:
-      - `pkgname`: Full name of the Python package to which the
-        information being read applies.  This is needed to construct
-        Extension objects properly.
-      - `directory`: Directory containing the package's __init__.py file.
-      - `reldir`: Relative directory path with which file names from
-        the information file will be joined.  This should be in POSIX
-        notation.  It will not be used to locate files.
-
-    """
-    pkginfo = read_package_info(directory, reldir)
-    pkginfo.extensions = [create_extension(ext, pkgname, reldir)
-                          for ext in pkginfo.extension]
-    return pkginfo
-
-
-def loadCollectionInfo(directory, reldir):
-    """Load package information for a collection.
-
-    :return: Package information object.
-
-    :Parameters:
-      - `directory`: Directory containing the collection's files.
-      - `reldir`: Relative directory path with which file names from
-        the information file will be joined.  This should be in POSIX
-        notation.  It will not be used to locate files.
-
-    """
-    pkginfo = read_package_info(directory, reldir)
-    if pkginfo.extension:
-        raise ValueError("extensions cannot be defined in collections")
-    pkginfo.extensions = []
-    return pkginfo
-
-
-def read_package_info(directory, reldir=None):
-    """Read the package information file from a specified directory.
-
-    :return: Package information object.
-
-    :Parameters:
-      - `directory`: Directory containing the collection's files.
-      - `reldir`: Relative directory path with which file names from
-        the information file will be joined.  This should be in POSIX
-        notation.  It will not be used to locate files.  It may be
-        omitted or None; if so, filenames are not 'relocated' relative
-        to where they are found.
-
-    """
-    path = os.path.join(directory, PACKAGE_CONF)
-    if os.path.exists(path):
-        path = os.path.realpath(path)
-        url = "file://" + urllib.pathname2url(path)
-        f = open(path)
-    else:
-        # Initialize using the cfgparser so we still get a package
-        # data object with the right attributes:
-        url = "<no file>"
-        f = StringIO("")
-    try:
-        p = cfgparser.Parser(f, url, PackageSchema(directory, reldir))
-        pkginfo = p.load()
-    finally:
-        f.close()
-    pkginfo.documentation = expand_globs(directory, reldir,
-                                         pkginfo.documentation)
-    pkginfo.header = expand_globs(directory, reldir, pkginfo.header)
-    pkginfo.script = expand_globs(directory, reldir, pkginfo.script)
-
-    # need to post-process the data_files so included directories are
-    # handled properly; distutils expects everything to be a file!
-    #
-    # XXX need tests!
-    #
-    datamap = {}
-    for dir, paths in pkginfo.data_files:
-        expand_data(directory, reldir, dir, paths, datamap)
-    if "." in datamap and datamap["."] == []:
-        del datamap["."]
-    pkginfo.data_files = datamap.items()
-
-    return pkginfo
-
-
-def expand_data(directory, reldir, targetdir, paths, datamap):
-    #
-    # `directory` is where we find things
-    #
-    # `reldir` is the relative location of directory in the source; we
-    # need it so we can rip it off of the values in `paths`
-    #
-    # `targetdir` is where we want the things in `paths` copied in
-    # POSIX notation
-    #
-    # `paths` is a list of paths to things we want copied, in POSIX
-    # notation, with `reldir` prepended
-    #
-    # `datamap` is a mapping from target directory -> [files], where
-    # files are really paths to actual files (not directories!) that
-    # are to be copied to the target directory; the file paths are
-    # given in POSIX notation and are prefixed by `reldir`
-    #
-    # All directories must be represented in the data map, even if
-    # they're empty.
-    #
-    targetdir = posixpath.normpath(targetdir)
-
-    # Make sure there's an entry for every directory we look at; that
-    # ensures distutils will create empty directories for us.
-    L = datamap.setdefault(targetdir, [])
-
-    if reldir:
-        prefix = posixpath.join(reldir, "")
-    else:
-        prefix = ""
-
-    # for files, add to the list, otherwise recursively scan
-    for src in paths:
-        # strip `reldir`, convert to local path notation
-        localpath = src[len(prefix):].replace("/", os.sep)
-        # find the referenced path
-        fullpath = os.path.join(directory, localpath)
-        if os.path.isfile(fullpath):
-            L.append(src)
-        else:
-            # directory; recurse
-            basename = os.path.basename(fullpath)
-            expand_data(
-                directory, reldir, posixpath.join(targetdir, basename),
-                [posixpath.join(src, name) for name in os.listdir(fullpath)],
-                datamap)
-
-
-def create_extension(section, pkgname, reldir):
-    """Create an `Extension` instance from a configuration section.
-
-    :Parameters:
-      - `section`: Section object from the configuration file.
-      - `pkgname`: Full name of the containing package.  This should
-        be an empty string or ``None`` if the extension is not in a
-        package.
-      - `reldir`: Directory in which the extension lives, relative to
-        the top of the distribution, given in POSIX notation.
-
-    """
-    kwargs = {}
-    if pkgname:
-        kwargs["name"] = "%s.%s" % (pkgname, section.name)
-    else:
-        kwargs["name"] = section.name
-    kwargs["sources"] = [posixpath.join(reldir, fn)
-                         for fn in section.source]
-    if section.define:
-        kwargs["define_macros"] = section.define
-    if section.undefine:
-        kwargs["undef_macros"] = undefs = []
-        for L in section.undefine:
-            undefs.extend(L)
-    if section.depends_on:
-        kwargs["depends"] = [posixpath.join(reldir, fn)
-                             for fn in section.depends_on]
-    if section.language:
-        kwargs["language"] = section.language[0]
-    if reldir and reldir != ".":
-        kwargs["include_dirs"] = [reldir]
-    return Extension(**kwargs)
-
-
-def expand_globs(directory, reldir, globlist):
-    """Expand glob patterns for directory.
-
-    :Parameters:
-      - `directory`: The path to the directory to which the glob
-        patterns are relative to.
-      - `reldir`: Base directory to use for returning glob expansions.
-        This should be a relative path in POSIX notation.  This is not
-        used for locating files.
-      - `globlist`: List of glob patterns in POSIX notation.  The
-        patterns may refer to child directories of `directory`.
-
-    :return: List of expansions in POSIX notation, using `reldir` as
-      the base directory.
-
-    Note that `directory` and `reldir` are two different names for the
-    same directory.
-
-    :warning: This function is not thread safe, as it changes the
-      current working directory while it is running.
-
-    """
-    results = []
-    pwd = os.getcwd()
-    os.chdir(directory)
-    try:
-        for g in globlist:
-            gs = g.replace("/", os.sep)
-            filenames = glob.glob(gs)
-            if not filenames:
-                raise ValueError(
-                    "filename pattern %r doesn't match any files" % g)
-            filenames = [fn.replace(os.sep, "/") for fn in filenames]
-            if reldir:
-                filenames = [posixpath.join(reldir, fn) for fn in filenames]
-            results += filenames
-    finally:
-        os.chdir(pwd)
-    return results
-
-
-# datatype functions referenced by the schema:
-
-def cpp_definition(s):
-    r"""Return a 2-tuple representing a CPP #define.
-
-    :rtype: (str, str or None)
-
-    The first element of the tuple is the name to define, and the
-    second is the value to use as the replacement text.  In the input,
-    the two parts should be separated by an equal sign.
-
-    >>> cpp_definition('NAME=VALUE')
-    ('NAME', 'VALUE')
-    >>> cpp_definition('NAME=')
-    ('NAME', '')
-
-    Whitespace around the equal sign are ignored:
-
-    >>> cpp_definition('NAME   =\tVALUE')
-    ('NAME', 'VALUE')
-
-    If there is no equal sign, and defininition with no replacement
-    text is used (equivalent to '#define NAME'):
-
-    >>> cpp_definition('NAME')
-    ('NAME', None)
-
-    ValueError is raised if there is an error in the input:
-
-    >>> cpp_definition('not-a-cpp-symbol')
-    Traceback (most recent call last):
-      ...
-    ValueError: not a valid C identifier: 'not-a-cpp-symbol'
-
-    """
-    if "=" in s:
-        name, value = s.split("=", 1)
-        name = name.rstrip()
-        value = value.lstrip()
-    else:
-        name = s
-        value = None
-    if _cpp_ident_match(name) is None:
-        raise ValueError("not a valid C identifier: %r" % name)
-    return name, value
-
-
-def cpp_names(s):
-    r"""Return a list of CPP symbols from a string.
-
-    :rtype: [str, ...]
-
-    >>> cpp_names('NAME')
-    ['NAME']
-    >>> cpp_names('NAME1 NAME_2 A_B_C A123')
-    ['NAME1', 'NAME_2', 'A_B_C', 'A123']
-
-    If something is included which is not a valid identifier for CPP,
-    ValueError is raised:
-
-    >>> cpp_names('not-really!')
-    Traceback (most recent call last):
-      ...
-    ValueError: not a valid C identifier: 'not-really!'
-
-    >>> cpp_names('NAME ANOTHER not-really!')
-    Traceback (most recent call last):
-      ...
-    ValueError: not a valid C identifier: 'not-really!'
-
-    """
-    names = s.split()
-    for name in names:
-        if _cpp_ident_match(name) is None:
-            raise ValueError("not a valid C identifier: %r" % name)
-    return names
-
-_cpp_ident_match = re.compile("[A-Za-z_][A-Za-z_0-9]*$").match
-
-
-def extension(section):
-    """Transform `section`, checking several fields for valid values.
-
-    :param section: Configuration section.
-    :return: Modified section.
-    """
-    section.name = section.getSectionName()
-    if not section.name:
-        raise ValueError("extensions must be named")
-    if not section.source:
-        raise ValueError("at least one extension source file must be listed")
-    if len(section.language) > 1:
-        raise ValueError("language can only be specified once")
-    return section
-
-
-def path_ref(s):
-    """Datatype for a local path reference.
-
-    :rtype: str
-
-    >>> path_ref('README.txt')
-    'README.txt'
-    >>> path_ref('./README.txt')
-    'README.txt'
-    >>> path_ref('foo/bar/file.txt')
-    'foo/bar/file.txt'
-
-    If a reference is not a relative path, ValueError is raised:
-
-    >>> path_ref('/absolute/path')
-    Traceback (most recent call last):
-      ...
-    ValueError: absolute paths are not allowed: '/absolute/path'
-
-    >>> path_ref('/')
-    Traceback (most recent call last):
-      ...
-    ValueError: absolute paths are not allowed: '/'
-
-    References which contain Windows drive letters are not allowed:
-
-    >>> path_ref('c:README.txt')
-    Traceback (most recent call last):
-      ...
-    ValueError: Windows drive letters are not allowed: 'c:README.txt'
-
-    If a reference is relative but points outside the local directory
-    hierarchy, ValueError is raised:
-
-    >>> path_ref('../somefile')
-    Traceback (most recent call last):
-      ...
-    ValueError: relative paths may not point outside the containing tree: '../somefile'
-
-    """
-    if not s:
-        raise ValueError("path references may not be empty")
-    if s.find(":") == 1:
-        # looks like a windows drive letter:
-        raise ValueError("Windows drive letters are not allowed: %r" % s)
-    p = posixpath.normpath(s)
-    if p[:1] == "/":
-        raise ValueError("absolute paths are not allowed: %r" % s)
-    parts = p.split("/")
-    if parts[0] == "..":
-        raise ValueError("relative paths may not point outside"
-                         " the containing tree: %r" % s)
-    return p
-
-
-class PackageSchema(cfgparser.Schema):
-    """Schema implementation with a <data-files> section type.
-
-    The <data-files> sections have keys that are glob-expanded (based
-    on information passed to the constructor) and combined into a
-    single .data_files member on the resulting package information
-    object.  The value of the .data_files attribute is suitable for
-    passing to the distutils.core.setup() function.
-
-    """
-
-    def __init__(self, directory, reldir):
-        cfgparser.Schema.__init__(
-            self,
-            ({"script": path_ref,
-              "documentation": path_ref,
-              "header": path_ref},
-             ["extension"], None),
-            {"extension": ({"source": path_ref, "depends-on": path_ref,
-                            "define" : cpp_definition, "undefine": cpp_names,
-                            "language": str,
-                            },
-                           (), extension),
-             }
-            )
-        self.__cf = None
-        self.__datafiles = None
-        self.__directory = directory
-        self.__reldir = reldir
-
-    def getConfiguration(self):
-        assert self.__cf is None
-        self.__cf = cfgparser.Schema.getConfiguration(self)
-        self.__cf.data_files = []
-        return self.__cf
-
-    def startSection(self, parent, typename, name):
-        if self.__datafiles is not None:
-            raise cfgparser.ConfigurationError(
-                "can't nest another section inside <data-files> section")
-        if typename == "data-files":
-            if not name:
-                raise cfgparser.ConfigurationError(
-                    "<data-files> section must have a name")
-            normname = posixpath.normpath(name)
-            for target, files in self.__cf.data_files:
-                if target == normname:
-                    raise cfgparser.ConfigurationError(
-                        "can't have two sections of the same name:"
-                        " <data-files %s>" % name)
-            self.__datafiles = []
-            self.__cf.data_files.append((normname, self.__datafiles))
-            # The return value is passed around, but that's it
-            return ()
-        else:
-            return cfgparser.Schema.startSection(self, parent, typename, name)
-
-    def endSection(self, parent, typename, name, child):
-        if self.__datafiles is None:
-            cfgparser.Schema.endSection(self, parent, typename, name, child)
-        else:
-            # mutate self.__datafiles since the reference from
-            # self.__cf.data_files is what's actually used
-            self.__datafiles[:] = expand_globs(self.__directory,
-                                               self.__reldir,
-                                               self.__datafiles)
-            self.__datafiles = None
-
-    def addValue(self, section, key, value):
-        if self.__datafiles is not None:
-            if value:
-                raise cfgparser.ConfigurationError(
-                    "each entry in a <data-files> section must be"
-                    " a single glob pattern")
-            self.__datafiles.append(key)
-        else:
-            cfgparser.Schema.addValue(self, section, key, value)

Deleted: zpkgtools/trunk/zpkgtools/publication.py
===================================================================
--- zpkgtools/trunk/zpkgtools/publication.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/publication.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,201 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Support for reading and generating publication metadata files.
-
-Such files include the PKG-INFO files generated by `distutils` as well
-as the PUBLICATION.cfg files used by **zpkg**.
-
-:var PUBLICATION_CONF: The default name of the file containing
-  publication data as used by **zpkg**.
-
-"""
-from distutils.dist import DistributionMetadata
-from distutils.util import rfc822_escape
-from email.Parser import Parser
-from StringIO import StringIO
-
-
-PUBLICATION_CONF = "PUBLICATION.cfg"
-
-
-# XXX The dump() and dumps() methods are very similar to the
-# DistributionMetadata.write_pkg_info() method, but don't constrain
-# where the data is written.  Much of this can be discarded if
-# portions of the PEP 262 patch (http://www.python.org/sf/562100) are
-# accepted.
-
-def dump(metadata, f):
-    """Write package metadata to a file in PKG-INFO format.
-
-    :param metadata: Metadata object to serialize.
-
-    :param f: Open file object to write to.
-
-    """
-    metadata_version = "1.0"
-    if (metadata.maintainer or metadata.maintainer_email
-        or metadata.url or metadata.get_classifiers()):
-        metadata_version = "1.1"
-    print >>f, "Metadata-Version:", metadata_version
-    print >>f, "Name:", metadata.get_name()
-    if metadata.version:
-        print >>f, "Version:", metadata.get_version()
-    if metadata.description:
-        print >>f, "Summary:", metadata.get_description()
-    if metadata.url:
-        print >>f, "Home-page:", metadata.get_url()
-    if metadata.author:
-        print >>f, "Author:", metadata.get_author()
-    if metadata.author_email:
-        print >>f, "Author-email:", metadata.get_author_email()
-    if metadata.maintainer:
-        print >>f, "Maintainer:", metadata.get_maintainer()
-    if metadata.maintainer_email:
-        print >>f, "Maintainer-email:", metadata.get_maintainer_email()
-    if metadata.license:
-        print >>f, "License:", metadata.get_license()
-    if metadata.url:
-        print >>f, "Download-URL:", metadata.url
-    if metadata.long_description:
-        long_desc = rfc822_escape(metadata.get_long_description())
-        print >>f, "Description:", long_desc
-    keywords = metadata.get_keywords()
-    if keywords:
-        print >>f, "Keywords:", ", ".join(keywords)
-    for platform in metadata.get_platforms():
-        print >>f, "Platform:", platform
-    for classifier in metadata.get_classifiers():
-        print >>f, "Classifier:", classifier
-
-
-def dumps(metadata):
-    """Return package metadata serialized in PKG-INFO format.
-
-    :return: String containing the serialized metadata.
-    :rtype: str
-
-    :param metadata: Metadata object to serialize.
-
-    """
-    sio = StringIO()
-    dump(metadata, sio)
-    return sio.getvalue()
-
-
-def load(f, versioninfo=False, metadata=None):
-    """Parse a PKG-INFO file and return a DistributionMetadata instance.
-
-    :return: Populated metadata object.
-    :rtype: `DistributionMetadata`
-
-    :param versioninfo: Flag indicating whether version-specific
-      information should be included.
-
-    :param metadata: Metadata object which should be populated from
-      the publication data.  If omitted, a fresh
-      `DistributionMetadata` instance will be used.
-
-    """
-    parser = Parser()
-    msg = parser.parse(f, headersonly=True)
-    return _loadmsg(msg, versioninfo, metadata)
-
-
-def loads(text, versioninfo=False, metadata=None):
-    """Parse PKG-INFO source text and return a DistributionMetadata instance.
-
-    :return: Populated metadata object.
-    :rtype: `DistributionMetadata`
-
-    :param versioninfo: Flag indicating whether version-specific
-      information should be included.
-
-    :param metadata: Metadata object which should be populated from
-      the publication data.  If omitted, a fresh
-      `DistributionMetadata` instance will be used.
-
-    """
-    parser = Parser()
-    msg = parser.parsestr(text, headersonly=True)
-    return _loadmsg(msg, versioninfo, metadata)
-
-
-def _loadmsg(msg, versioninfo, metadata=None):
-    if metadata is None:
-        metadata = DistributionMetadata()
-
-    if versioninfo:
-        metadata.version = _get_single_header(msg, "Version")
-    metadata.download_url = _get_single_header(msg, "Download-URL")
-    metadata.name = _get_single_header(msg, "Name")
-    metadata.author = _get_single_header(msg, "Author")
-    metadata.author_email = _get_single_header(msg, "Author-email")
-    metadata.maintainer = _get_single_header(msg, "Maintainer")
-    metadata.maintainer_email = _get_single_header(msg, "Maintainer-email")
-    metadata.url = _get_single_header(msg, "Home-page")
-    metadata.license = _get_single_header(msg, "License")
-    metadata.description = _get_single_header(msg, "Summary")
-    metadata.long_description = _get_single_header(msg, "Description")
-
-    keywords = _get_single_header(msg, "Keywords", "")
-    keywords = [s.strip() for s in keywords.split(",") if s.strip()]
-    metadata.keywords = keywords or None
-
-    platforms = msg.get_all("Platform")
-    if platforms:
-        metadata.platforms = platforms
-
-    classifiers = msg.get_all("Classifier")
-    if classifiers:
-        metadata.classifiers = classifiers
-
-    return metadata
-
-
-def _get_single_header(msg, name, default=None):
-    """Return the value for a header that only occurs once in the input.
-
-    :raises ValueError: If the header occurs more than once.
-
-    """
-    headers = msg.get_all(name)
-    if headers and len(headers) > 1:
-        raise ValueError("header %r can only be given once" % name)
-    if headers:
-        v = headers[0]
-        if v == "UNKNOWN":
-            return None
-        else:
-            return v
-    else:
-        return default
-
-
-
-ALPHA  = "Development Status :: 3 - Alpha"
-BETA   = "Development Status :: 4 - Beta"
-STABLE = "Development Status :: 5 - Production/Stable"
-
-def set_development_status(metadata, status):
-    if not metadata.classifiers:
-        metadata.classifiers = [status]
-        return
-    for i in range(len(metadata.classifiers)):
-        classifier = metadata.classifiers[i]
-        parts = [s.strip() for s in classifier.lower().split("::")]
-        if parts[0] == "development status":
-            metadata.classifiers[i] = status
-            break
-    else:
-        metadata.classifiers.append(status)

Modified: zpkgtools/trunk/zpkgtools/runlog.py
===================================================================
--- zpkgtools/trunk/zpkgtools/runlog.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/runlog.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -16,7 +16,7 @@
 import os
 import sys
 
-from zpkgtools import loggingapi as logging
+from zpkgsetup import loggingapi as logging
 
 
 def report_command(cmd):

Deleted: zpkgtools/trunk/zpkgtools/setup.py
===================================================================
--- zpkgtools/trunk/zpkgtools/setup.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/setup.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,217 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Generator for distutils setup.py files."""
-
-import errno
-import os
-import posixpath
-import re
-import sys
-
-from zpkgtools import include
-from zpkgtools import package
-from zpkgtools import publication
-
-
-class SetupContext:
-    """Object representing the arguments to distutils.core.setup()."""
-
-    def __init__(self, pkgname, version, setup_file):
-        self._working_dir = os.path.dirname(os.path.abspath(setup_file))
-        self._pkgname = pkgname
-        self.version = version
-        self.packages = []
-        self.package_data = {}
-        self.package_dir = {}
-        self.ext_modules = []
-        self.scripts = []
-        self.platforms = None
-        self.classifiers = None
-        self.data_files = []
-
-    def initialize(self):
-        self.load_metadata(
-            os.path.join(self._working_dir, self._pkgname,
-                         publication.PUBLICATION_CONF))
-        pkgdir = os.path.join(self._working_dir, self._pkgname)
-        self.scan(self._pkgname, pkgdir, self._pkgname)
-        depsdir = os.path.join(self._working_dir, "Dependencies")
-        if os.path.isdir(depsdir):
-            depnames = os.listdir(depsdir)
-            suffix = "-%s-%s" % (self._pkgname, self.version)
-            for name in depnames:
-                if name != "Includes" and not name.endswith(suffix):
-                    # an unexpected name; we didn't put this here!
-                    print >>sys.stderr, \
-                          "unexpected name in Dependencies/: %r" % name
-                    continue
-                depdir = os.path.join(depsdir, name)
-                if not os.path.isdir(depdir):
-                    # a file; we didn't put this here either!
-                    print >>sys.stderr, \
-                          "unexpected file in Dependencies/: %r" % name
-                    continue
-                depname = name[:-len(suffix)]
-                pkgdir = os.path.join(depdir, depname)
-                reldir = posixpath.join("Dependencies", name, depname)
-                self.scan(depname, pkgdir, reldir)
-            includes_dir = os.path.join(depsdir, "Includes")
-            if os.path.isdir(includes_dir):
-                for ext in self.ext_modules:
-                    ext.include_dirs.append(includes_dir)
-
-    def setup(self):
-        kwargs = self.__dict__.copy()
-        for name in self.__dict__:
-            if name[0] == "_":
-                del kwargs[name]
-        if "--debug" in sys.argv:
-            import pprint
-            try:
-                pprint.pprint(kwargs)
-            except IOError, e:
-                if e.errno != errno.EPIPE:
-                    raise
-        else:
-            if sys.version_info < (2, 3):
-                from distutils.dist import DistributionMetadata
-                DistributionMetadata.classifiers = None
-                DistributionMetadata.download_url = None
-            try:
-                from setuptools import setup
-            except ImportError:
-                # package_data can't be handled this way ;-(
-                if self.package_data:
-                    print >>sys.stderr, (
-                        "can't import setuptools;"
-                        " some package data will not be properly installed")
-                from distutils.core import setup
-            setup(**kwargs)
-
-    def load_metadata(self, path):
-        f = open(path, "rU")
-        publication.load(f, metadata=self)
-        if self.platforms:
-            self.platforms = ", ".join(self.platforms)
-        m = re.match(r"\d+\.\d+(\.\d+)?(?:(?P<status>[ab])\d*)?$",
-                     self.version)
-        if m is not None:
-            devstatus = publication.STABLE
-            status = m.group("status")
-            if status == "a":
-                devstatus = publication.ALPHA
-            elif status == "b":
-                devstatus = publication.BETA
-            publication.set_development_status(self, devstatus)
-
-    def scan(self, name, directory, reldir):
-        init_py = os.path.join(directory, "__init__.py")
-        if os.path.isfile(init_py):
-            self.scan_package(name, directory, reldir)
-        else:
-            self.scan_collection(name, directory, reldir)
-
-    def scan_collection(self, name, directory, reldir):
-        # load the collection metadata
-        pkginfo = package.loadCollectionInfo(directory, reldir)
-        self.scan_basic(pkginfo)
-
-    def scan_package(self, name, directory, reldir):
-        # load the package metadata
-        pkginfo = package.loadPackageInfo(name, directory, reldir)
-        self.scan_basic(pkginfo)
-        self.ext_modules.extend(pkginfo.extensions)
-        self.add_package_dir(name, reldir)
-
-        # scan the files in the directory:
-        files = include.filter_names(os.listdir(directory))
-        for fn in files:
-            fnbase, ext = os.path.splitext(fn)
-            path = os.path.join(directory, fn)
-            if os.path.isdir(path):
-                init_py = os.path.join(path, "__init__.py")
-                if os.path.isfile(init_py):
-                    # if this package is published separately, skip it:
-                    # XXX we shouldn't actually need this if we only
-                    # use this class to scan in the generated
-                    # distributions
-                    if os.path.isfile(
-                        os.path.join(path, publication.PUBLICATION_CONF)):
-                        continue
-                    pkgname = "%s.%s" % (name, fn)
-                    self.scan_package(
-                        pkgname, path, posixpath.join(reldir, fn))
-                else:
-                    # an ordinary directory
-                    self.scan_directory(name, path, fn)
-            # Only add the file as package data if it's not a Python
-            # source file; Python files are copied in automatically.
-            elif not fn.endswith(".py"):
-                self.add_package_file(name, fn)
-
-        # We need to check that any files that were labelled as
-        # scripts or application data aren't copied in as package
-        # data; they shouldn't be installed into the package itself.
-        #
-        # XXX I'm not sure whether documentation files should be
-        # removed from package_data or not, given that there's no spec
-        # for installing documentation other than for RPMs.
-        #
-        relbase = posixpath.join(reldir, "")
-        pkgfiles = self.package_data.get(name, [])
-        non_pkgdata = pkginfo.script + pkginfo.header
-        for dir, files in pkginfo.data_files:
-            non_pkgdata.extend(files)
-        for ext in pkginfo.extensions:
-            for fn in ext.sources + getattr(ext, "depends", []):
-                if fn not in non_pkgdata:
-                    non_pkgdata.append(fn)
-        for fn in non_pkgdata:
-            pkgdatapath = fn[len(relbase):]
-            if pkgdatapath in pkgfiles:
-                pkgfiles.remove(pkgdatapath)
-
-    def scan_directory(self, pkgname, directory, reldir):
-        """Scan a data directory, adding files to package_data."""
-        files = include.filter_names(os.listdir(directory))
-        for fn in files:
-            path = os.path.join(directory, fn)
-            if os.path.isdir(path):
-                self.scan_directory(pkgname,
-                                    os.path.join(directory, fn),
-                                    posixpath.join(reldir, fn))
-            else:
-                self.add_package_file(pkgname, posixpath.join(reldir, fn))
-
-    def scan_basic(self, pkginfo):
-        self.scripts.extend(pkginfo.script)
-        if pkginfo.data_files:
-            if self.data_files:
-                # merge:
-                d = dict(self.data_files)
-                for dir, files in pkginfo.data_files:
-                    L = d.setdefault(dir, [])
-                    L.extend(files)
-                self.data_files = d.items()
-            else:
-                self.data_files = pkginfo.data_files
-
-    def add_package_dir(self, pkgname, reldir):
-        self.packages.append(pkgname)
-        if pkgname.replace(".", "/") != reldir:
-            self.package_dir[pkgname] = reldir
-
-    def add_package_file(self, pkgname, relfn):
-        L = self.package_data.setdefault(pkgname, [])
-        L.append(relfn)

Modified: zpkgtools/trunk/zpkgtools/tests/input/packages.map
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/input/packages.map	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/input/packages.map	2004-06-17 16:12:11 UTC (rev 25887)
@@ -4,4 +4,3 @@
 collection:collection-2  collection-2/
 
 package                  package/
-package2                 package2/

Modified: zpkgtools/trunk/zpkgtools/tests/runtests.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/runtests.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/runtests.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -27,36 +27,13 @@
 TOPDIR = os.path.dirname(PKGDIR)
 
 
-def load_tests(name):
-    name = "zpkgtools.tests." + name
-    __import__(name)
-    mod = sys.modules[name]
-    return mod.test_suite()
-
-
 def test_suite():
-    L = []
-    for fn in os.listdir(TESTDIR):
-        name, ext = os.path.splitext(fn)
-        if name[:4] == "test" and ext == ".py":
-            L.append(load_tests(name))
-    suite = L.pop()
-    for t in L:
-        suite.addTest(t)
-    return suite
+    from zpkgsetup.tests.runtests import make_directory_suite
+    return make_directory_suite("zpkgtools.tests", TESTDIR)
 
 
-class MyTestProgram(unittest.TestProgram):
-    """Test runner program that doesn't use docstrings as descriptions."""
-
-    def runTests(self):
-        if self.testRunner is None:
-            self.testRunner = unittest.TextTestRunner(descriptions=False,
-                                                      verbosity=self.verbosity)
-        unittest.TestProgram.runTests(self)
-
-
 if __name__ == "__main__":
     if TOPDIR not in sys.path:
         sys.path.insert(0, TOPDIR)
+    from zpkgsetup.tests.runtests import MyTestProgram
     MyTestProgram(defaultTest="test_suite")

Modified: zpkgtools/trunk/zpkgtools/tests/test_app.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_app.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_app.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -22,12 +22,13 @@
 
 from StringIO import StringIO
 
+from zpkgsetup import publication
+
 import zpkgtools
 
 from zpkgtools import app
 from zpkgtools import include
 from zpkgtools import loader
-from zpkgtools import publication
 
 
 CMD = "./foo/bar.py"

Deleted: zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_cfgparser.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,162 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests for zpkgtools.cfgparser."""
-
-import unittest
-
-from StringIO import StringIO
-
-from zpkgtools import cfgparser
-
-
-class SimpleSection:
-
-    finished = False
-    ending_parent = None
-    ending_typename = None
-    ending_name = None
-
-    def __init__(self, parent=None, typename=None, name=None):
-        self.parent = parent
-        self.typename = typename
-        self.name = name
-
-
-class AnythingGoesSchema:
-
-    def getConfiguration(self):
-        return SimpleSection()
-
-    def startSection(self, parent, typename, name):
-        return SimpleSection(parent, typename, name)
-
-    def finishSection(self, section):
-        section.finished = True
-        return section
-
-    def endSection(self, parent, typename, name, child):
-        child.ending_parent = parent
-        child.ending_typename = typename
-        child.ending_name = name
-        if not hasattr(parent, typename):
-            setattr(parent, typename, [])
-        getattr(parent, typename).append(child)
-        self.finishSection(child)
-
-    def addValue(self, section, key, value):
-        key = key.lower().replace("-", "_")
-        if not hasattr(section, key):
-            setattr(section, key, [])
-        getattr(section, key).append(value)
-
-
-class ParserTestCase(unittest.TestCase):
-
-    schema = AnythingGoesSchema()
-
-    def createParser(self, text=""):
-        sio = StringIO(text)
-        self.parser = cfgparser.Parser(sio, "<some-url>", self.schema)
-        return self.parser
-
-    def test_replace(self):
-        # "legal" values are those that are legal in ZConfig
-        eq = self.assertEqual
-        raises = self.assertRaises
-        replace = self.createParser().replace
-
-        # some legal values that don't have '$':
-        eq(replace(""), "")
-        eq(replace(" foo bar "), " foo bar ")
-        eq(replace("x"), "x")
-
-        # legal, supported values with '$':
-        eq(replace("$$"), "$")
-        eq(replace("$$$$"), "$$")
-        eq(replace("$$xyz$$"), "$xyz$")
-
-        # legal, unsupported values (all have '$'):
-        raises(cfgparser.ConfigurationError, replace, "$foo")
-        raises(cfgparser.ConfigurationError, replace, "${foo-bar}")
-
-        # illegal values:
-        raises(cfgparser.ConfigurationError, replace, "$")
-        raises(cfgparser.ConfigurationError, replace, "foo$")
-
-    def test_schema_use(self):
-        eq = self.assertEqual
-        p = self.createParser("""
-            # This is a comment.
-
-            key value 1
-            key value 2
-            <section/>
-            <section foo/>
-            <section>
-              key  value 3
-            </section>
-            <section splat>
-              <inner>
-                key value 5
-              </inner>
-              key value 4
-            </section>
-            """)
-        cf = p.load()
-        self.check_section(cf, None, None, None, key=["value 1", "value 2"])
-        s1, s2, s3, s4 = cf.section
-        self.check_section(s1, cf, None, "section")
-        self.check_section(s2, cf, "foo", "section")
-        self.check_section(s3, cf, None, "section", key=["value 3"])
-        self.check_section(s4, cf, "splat", "section", key=["value 4"])
-        inner, = s4.inner
-        self.check_section(inner, s4, None, "inner", key=["value 5"])
-
-    def check_section(self, section, parent, name, typename, **attrs):
-        self.assert_(section.finished)
-        self.assert_(section.parent is parent)
-        self.assert_(section.parent is section.ending_parent)
-        self.assertEqual(section.name, name)
-        self.assertEqual(section.name, section.ending_name)
-        self.assertEqual(section.typename, typename)
-        self.assertEqual(section.typename, section.ending_typename)
-        for name, value in attrs.iteritems():
-            v = getattr(section, name)
-            self.assertEqual(v, value)
-
-
-class SchemaTestCase(unittest.TestCase):
-
-    top_level_converted = False
-
-    def setUp(self):
-        self.schema = cfgparser.Schema(
-            ({}, [], self.top_level_conversion))
-
-    def top_level_conversion(self, section):
-        self.top_level_converted = True
-        return section
-
-    def test_getConfiguration(self):
-        cf = self.schema.getConfiguration()
-        self.failIf(self.top_level_converted)
-
-
-def test_suite():
-    suite = unittest.makeSuite(ParserTestCase)
-    suite.addTest(unittest.makeSuite(SchemaTestCase))
-    return suite
-
-if __name__ == "__main__":
-    unittest.main(defaultTest="test_suite")

Modified: zpkgtools/trunk/zpkgtools/tests/test_config.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_config.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_config.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -18,7 +18,7 @@
 
 from StringIO import StringIO
 
-from zpkgtools import cfgparser
+from zpkgsetup import cfgparser
 from zpkgtools import config
 
 

Modified: zpkgtools/trunk/zpkgtools/tests/test_include.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_include.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_include.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -23,7 +23,8 @@
 from os.path import join
 from StringIO import StringIO
 
-from zpkgtools import cfgparser
+from zpkgsetup import cfgparser
+
 from zpkgtools import include
 from zpkgtools import loader
 

Deleted: zpkgtools/trunk/zpkgtools/tests/test_package.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_package.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_package.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,213 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests for zpkgtools.package."""
-
-import doctest
-import os.path
-import shutil
-import tempfile
-import unittest
-
-from distutils.core import Extension
-from StringIO import StringIO
-
-from zpkgtools import cfgparser
-from zpkgtools import package
-
-
-class PackageInfoTestCase(unittest.TestCase):
-
-    def setUp(self):
-        self.tmpdir = tempfile.mkdtemp(prefix="test_package_")
-
-    def tearDown(self):
-        shutil.rmtree(self.tmpdir)
-
-    def write_config(self, text):
-        self.write_file(package.PACKAGE_CONF, text)
-
-    def write_file(self, name, text):
-        f = open(os.path.join(self.tmpdir, name), "w")
-        f.write(text)
-        f.close()
-
-    def test_empty_pkginfo(self):
-        self.write_config("# empty configuration file\n")
-        pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
-        eq = self.assertEqual
-        eq(pkginfo.extensions, [])
-        eq(pkginfo.documentation, [])
-        eq(pkginfo.script, [])
-
-    def test_missing_pkginfo(self):
-        pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
-        eq = self.assertEqual
-        eq(pkginfo.extensions, [])
-        eq(pkginfo.documentation, [])
-        eq(pkginfo.script, [])
-
-    def test_nonempty_pkginfo(self):
-        self.write_config("documentation  doc/README.txt\n"
-                          "script         bin/runme.py\n"
-                          "<extension cricket>\n"
-                          "  source     jiminy.c\n"
-                          "  define     FOO\n"
-                          "  define     BAR = splat\n"
-                          "  undefine   CRUNCHY NUGGET\n"
-                          "  depends-on cricket.h\n"
-                          "  depends-on innerds.c\n"
-                          "  language   C\n"
-                          "</extension>\n")
-        os.mkdir(os.path.join(self.tmpdir, "doc"))
-        self.write_file(os.path.join("doc", "README.txt"),
-                        "docs go here")
-        os.mkdir(os.path.join(self.tmpdir, "bin"))
-        self.write_file(os.path.join("bin", "runme.py"),
-                        "#!/bin/sh\nexit\n")
-        pkginfo = package.loadPackageInfo("foo", self.tmpdir, "bar")
-        eq = self.assertEqual
-        eq(len(pkginfo.extensions), 1)
-        eq(pkginfo.documentation, ["bar/doc/README.txt"])
-        eq(pkginfo.script, ["bar/bin/runme.py"])
-
-        ext = pkginfo.extensions[0]
-        self.assert_(isinstance(ext, Extension))
-        eq(ext.name, "foo.cricket")
-        eq(ext.sources, ["bar/jiminy.c"])
-        eq(ext.depends, ["bar/cricket.h", "bar/innerds.c"])
-        eq(ext.define_macros, [("FOO", None), ("BAR", "splat")])
-        eq(ext.undef_macros, ["CRUNCHY", "NUGGET"])
-        eq(ext.language, "C")
-
-    def test_broken_extension_too_many_languages(self):
-        self.write_config("<extension cricket>\n"
-                          "  source     jiminy.c\n"
-                          "  language   C\n"
-                          "  language   C++\n"
-                          "</extension>\n")
-        self.assertRaises(cfgparser.ConfigurationError,
-                          package.loadPackageInfo, "foo", self.tmpdir, "bar")
-
-    def test_broken_extension_without_name(self):
-        self.write_config("<extension>\n"
-                          "  source  jiminy.c\n"
-                          "</extension>\n")
-        self.assertRaises(cfgparser.ConfigurationError,
-                          package.loadPackageInfo, "foo", self.tmpdir, "bar")
-
-    def test_broken_extension_no_source(self):
-        self.write_config("<extension cricket/>")
-        self.assertRaises(cfgparser.ConfigurationError,
-                          package.loadPackageInfo, "foo", self.tmpdir, "bar")
-
-    def test_collection_empty_pkginfo(self):
-        self.write_config("# empty configuration file\n")
-        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
-        eq = self.assertEqual
-        eq(pkginfo.extensions, [])
-        eq(pkginfo.documentation, [])
-        eq(pkginfo.script, [])
-
-    def test_collection_missing_pkginfo(self):
-        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
-        eq = self.assertEqual
-        eq(pkginfo.extensions, [])
-        eq(pkginfo.documentation, [])
-        eq(pkginfo.script, [])
-
-    def test_collection_pkginfo(self):
-        self.write_config("documentation  doc/*\n"
-                          "script         bin/*.py\n")
-        os.mkdir(os.path.join(self.tmpdir, "doc"))
-        self.write_file(os.path.join("doc", "README.txt"),
-                        "docs go here")
-        os.mkdir(os.path.join(self.tmpdir, "bin"))
-        self.write_file(os.path.join("bin", "runme.py"),
-                        "#!/bin/sh\nexit\n")
-        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
-        eq = self.assertEqual
-        eq(len(pkginfo.extensions), 0)
-        eq(pkginfo.documentation, ["doc/README.txt"])
-        eq(pkginfo.script, ["bin/runme.py"])
-
-    def test_collection_pkginfo_disallows_extensions(self):
-        self.write_config("<extension foo>\n"
-                          "  source  foo.c\n"
-                          "</extension>\n")
-        self.assertRaises(ValueError, package.loadCollectionInfo,
-                          self.tmpdir, None)
-
-    def test_data_files_1(self):
-        self.write_config("<data-files etc>\n"
-                          "  foo*\n"
-                          "</data-files>\n")
-        self.write_file("foo1.conf", "config goes here")
-        self.write_file("foo2.conf", "config goes here")
-        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
-        pkginfo.data_files[0][1].sort()
-        self.assertEqual(pkginfo.data_files,
-                         [("etc", ["foo1.conf", "foo2.conf"])])
-
-    def test_data_files_2(self):
-        self.write_config("<data-files var>\n"
-                          "  foo2.conf\n"
-                          "</data-files>\n"
-                          "<data-files etc>\n"
-                          "  foo1.conf\n"
-                          "</data-files>\n")
-        self.write_file("foo1.conf", "config goes here")
-        self.write_file("foo2.conf", "config goes here")
-        pkginfo = package.loadCollectionInfo(self.tmpdir, None)
-        pkginfo.data_files.sort()
-        self.assertEqual(pkginfo.data_files,
-                         [("etc", ["foo1.conf"]),
-                           ("var", ["foo2.conf"])])
-
-    def test_data_files_error_has_value(self):
-        self.write_config("<data-files etc>\n"
-                          "  foo bar\n"
-                          "</data-files>\n")
-        self.assertRaises(cfgparser.ConfigurationError,
-                          package.loadCollectionInfo, self.tmpdir, None)
-
-    def test_data_files_error_has_nested_section(self):
-        self.write_config("<data-files etc>\n"
-                          "  <extension foo>\n"
-                          "  </extension>\n"
-                          "</data-files>\n")
-        self.assertRaises(cfgparser.ConfigurationError,
-                          package.loadCollectionInfo, self.tmpdir, None)
-
-    def test_data_files_error_section_without_name(self):
-        self.write_config("<data-files>\n"
-                          "</data-files>\n")
-        self.assertRaises(cfgparser.ConfigurationError,
-                          package.loadCollectionInfo, self.tmpdir, None)
-
-    def test_data_files_error_sections_with_same_name(self):
-        self.write_config("<data-files etc>\n"
-                          "</data-files>\n"
-                          "<data-files etc/>\n"
-                          "</data-files>\n")
-        self.assertRaises(cfgparser.ConfigurationError,
-                          package.loadCollectionInfo, self.tmpdir, None)
-
-
-def test_suite():
-    suite = doctest.DocTestSuite("zpkgtools.package")
-    suite.addTest(unittest.makeSuite(PackageInfoTestCase))
-    return suite
-
-if __name__ == "__main__":
-    unittest.main(defaultTest="test_suite")

Deleted: zpkgtools/trunk/zpkgtools/tests/test_publication.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_publication.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_publication.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,59 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests for zpkgtools.publication
-
-$Id: test_publication.py,v 1.1 2004/06/14 20:46:41 fdrake Exp $
-"""
-import unittest
-
-from zpkgtools import publication
-
-
-class DevelopmentStatusTestCase(unittest.TestCase):
-
-    def test_set_development_status_replace_1(self):
-        metadata = publication.loads(
-            "Name: foo\n"
-            "Classifier: Development Status:: 3 - Alpha\n")
-        publication.set_development_status(metadata, publication.BETA)
-        self.assertEqual(metadata.classifiers, [publication.BETA])
-
-    def test_set_development_status_replace_2(self):
-        metadata = publication.loads(
-            "Name: foo\n"
-            "Classifier: Environment :: Console\n"
-            "Classifier: Development Status:: 3 - Alpha\n"
-            "Classifier: Intended Audience :: Developers\n")
-        publication.set_development_status(metadata, publication.BETA)
-        self.assertEqual(metadata.classifiers, [
-            "Environment :: Console",
-            publication.BETA,
-            "Intended Audience :: Developers",
-            ])
-
-    def test_set_development_status_append(self):
-        metadata = publication.loads(
-            "Name: foo\n"
-            "Classifier: Environment :: Console\n"
-            "Classifier: Intended Audience :: Developers\n")
-        publication.set_development_status(metadata, publication.BETA)
-        self.assertEqual(metadata.classifiers, [
-            "Environment :: Console",
-            "Intended Audience :: Developers",
-            publication.BETA,
-            ])
-
-
-def test_suite():
-    return unittest.makeSuite(DevelopmentStatusTestCase)

Deleted: zpkgtools/trunk/zpkgtools/tests/test_setup.py
===================================================================
--- zpkgtools/trunk/zpkgtools/tests/test_setup.py	2004-06-17 15:52:08 UTC (rev 25886)
+++ zpkgtools/trunk/zpkgtools/tests/test_setup.py	2004-06-17 16:12:11 UTC (rev 25887)
@@ -1,57 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests of zpkgtools.setup."""
-
-import os
-import unittest
-
-from zpkgtools import publication
-from zpkgtools import setup
-
-
-here = os.path.dirname(os.path.abspath(__file__))
-
-
-class SetupContextTestCase(unittest.TestCase):
-
-    def test_python_files_as_data(self):
-        packagedir = os.path.join(here, "input", "package")
-        publicationcfg = os.path.join(packagedir, publication.PUBLICATION_CONF)
-        setupfile = os.path.join(here, "input", "setup.py")
-        f = open(publicationcfg, "w")
-        f.write("Metadata-version: 1.0\n"
-                "Name: foo\n")
-        f.close()
-        try:
-            context = setup.SetupContext("package", "0.1.234", setupfile)
-            context.initialize()
-            context.package_data["package"].sort()
-            self.assertEqual(context.package_data,
-                             {"package": ["PUBLICATION.cfg",
-                                          "datadir/justdata.py"]})
-        finally:
-            os.unlink(publicationcfg)
-
-    def test_extension_sources_are_not_package_data(self):
-        packagedir = os.path.join(here, "input", "package2")
-        setupfile = os.path.join(here, "input", "setup.py")
-        context = setup.SetupContext("package2", "0.1.234", setupfile)
-        context.initialize()
-        context.package_data["package2"].sort()
-        self.assertEqual(context.package_data,
-                         {"package2": ["PUBLICATION.cfg", "SETUP.cfg"]})
-
-
-def test_suite():
-    return unittest.makeSuite(SetupContextTestCase)




More information about the Zope-CVS mailing list